better impl of repository id lookup methods returning Optional

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-04-11 22:18:14 +02:00
parent f27dc7d3a8
commit f6b366fa41
10 changed files with 81 additions and 31 deletions

View File

@ -74,6 +74,9 @@ public interface BookAuthorRepository {
@Find @Find
Book byTitleAndDate(String title, LocalDate publicationDate); Book byTitleAndDate(String title, LocalDate publicationDate);
@Find
Optional<Book> maybeByTitleAndDate(String title, LocalDate publicationDate);
@Find @Find
Book bookById(@By("isbn") String id); Book bookById(@By("isbn") String id);

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.processor.annotation; package org.hibernate.processor.annotation;
import org.checkerframework.checker.nullness.qual.Nullable;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import java.util.List; import java.util.List;
import java.util.StringTokenizer; import java.util.StringTokenizer;
@ -24,6 +26,7 @@ public abstract class AbstractCriteriaMethod extends AbstractFinderMethod {
AnnotationMetaEntity annotationMetaEntity, AnnotationMetaEntity annotationMetaEntity,
ExecutableElement method, ExecutableElement method,
String methodName, String entity, String methodName, String entity,
@Nullable String containerType,
boolean belongsToDao, boolean belongsToDao,
String sessionType, String sessionName, String sessionType, String sessionName,
List<String> fetchProfiles, List<String> fetchProfiles,
@ -35,8 +38,9 @@ public abstract class AbstractCriteriaMethod extends AbstractFinderMethod {
List<Boolean> multivalued, List<Boolean> multivalued,
List<Boolean> paramPatterns, List<Boolean> paramPatterns,
String fullReturnType) { String fullReturnType) {
super(annotationMetaEntity, method, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, super(annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName,
paramNames, paramTypes, orderBys, addNonnullAnnotation, convertToDataExceptions, fullReturnType); fetchProfiles, paramNames, paramTypes, orderBys, addNonnullAnnotation, convertToDataExceptions,
fullReturnType);
this.multivalued = multivalued; this.multivalued = multivalued;
this.paramPatterns = paramPatterns; this.paramPatterns = paramPatterns;
} }

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.processor.annotation; package org.hibernate.processor.annotation;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
@ -19,6 +20,7 @@ import static org.hibernate.processor.util.StringUtil.getUpperUnderscoreCaseFrom
* @author Gavin King * @author Gavin King
*/ */
public abstract class AbstractFinderMethod extends AbstractQueryMethod { public abstract class AbstractFinderMethod extends AbstractQueryMethod {
final @Nullable String containerType;
final String entity; final String entity;
final List<String> fetchProfiles; final List<String> fetchProfiles;
@ -27,6 +29,7 @@ public abstract class AbstractFinderMethod extends AbstractQueryMethod {
ExecutableElement method, ExecutableElement method,
String methodName, String methodName,
String entity, String entity,
@Nullable String containerType,
boolean belongsToDao, boolean belongsToDao,
String sessionType, String sessionType,
String sessionName, String sessionName,
@ -46,6 +49,7 @@ public abstract class AbstractFinderMethod extends AbstractQueryMethod {
convertToDataExceptions, convertToDataExceptions,
fullReturnType ); fullReturnType );
this.entity = entity; this.entity = entity;
this.containerType = containerType;
this.fetchProfiles = fetchProfiles; this.fetchProfiles = fetchProfiles;
} }

View File

@ -1482,9 +1482,9 @@ public class AnnotationMetaEntity extends AnnotationMeta {
Diagnostic.Kind.ERROR ); Diagnostic.Kind.ERROR );
} }
else { else {
if ( containerType != null ) { if ( containerType != null
&& !containerType.getQualifiedName().contentEquals(OPTIONAL) ) {
// multiple results, so it has to be a criteria finder // multiple results, so it has to be a criteria finder
// or, alternatively, Optional, which for now we treat similarly
createCriteriaFinder( method, declaredType, containerType.toString(), entity ); createCriteriaFinder( method, declaredType, containerType.toString(), entity );
} }
else { else {
@ -1497,6 +1497,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
message( parameter, "ordering would have no effect", Diagnostic.Kind.ERROR); message( parameter, "ordering would have no effect", Diagnostic.Kind.ERROR);
} }
} }
final String containerTypeName = containerType==null ? null : OPTIONAL;
final long parameterCount = final long parameterCount =
method.getParameters().stream() method.getParameters().stream()
.filter(AnnotationMetaEntity::isFinderParameterMappingToAttribute) .filter(AnnotationMetaEntity::isFinderParameterMappingToAttribute)
@ -1506,10 +1507,10 @@ public class AnnotationMetaEntity extends AnnotationMeta {
message( method, "missing parameter", Diagnostic.Kind.ERROR ); message( method, "missing parameter", Diagnostic.Kind.ERROR );
break; break;
case 1: case 1:
createSingleParameterFinder( method, declaredType, entity ); createSingleParameterFinder( method, declaredType, entity, containerTypeName );
break; break;
default: default:
createMultipleParameterFinder( method, declaredType, entity ); createMultipleParameterFinder( method, declaredType, entity, containerTypeName );
} }
} }
} }
@ -1771,7 +1772,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
} }
} }
private void createMultipleParameterFinder(ExecutableElement method, TypeMirror returnType, TypeElement entity) { private void createMultipleParameterFinder(
ExecutableElement method, TypeMirror returnType, TypeElement entity, @Nullable String containerType) {
final String methodName = method.getSimpleName().toString(); final String methodName = method.getSimpleName().toString();
final List<String> paramNames = parameterNames( method, entity ); final List<String> paramNames = parameterNames( method, entity );
final List<String> paramTypes = parameterTypes( method ); final List<String> paramTypes = parameterTypes( method );
@ -1796,6 +1798,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
this, method, this, method,
methodName, methodName,
returnType.toString(), returnType.toString(),
containerType,
paramNames, paramNames,
paramTypes, paramTypes,
parameterNullability(method, entity), parameterNullability(method, entity),
@ -1816,7 +1819,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
this, method, this, method,
methodName, methodName,
returnType.toString(), returnType.toString(),
null, containerType,
paramNames, paramNames,
paramTypes, paramTypes,
parameterNullability(method, entity), parameterNullability(method, entity),
@ -1835,7 +1838,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
} }
} }
private void createSingleParameterFinder(ExecutableElement method, TypeMirror returnType, TypeElement entity) { private void createSingleParameterFinder(
ExecutableElement method, TypeMirror returnType, TypeElement entity, @Nullable String containerType) {
final String methodName = method.getSimpleName().toString(); final String methodName = method.getSimpleName().toString();
final VariableElement parameter = final VariableElement parameter =
method.getParameters().stream() method.getParameters().stream()
@ -1855,6 +1859,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
this, method, this, method,
methodName, methodName,
returnType.toString(), returnType.toString(),
containerType,
paramNames, paramNames,
paramTypes, paramTypes,
repository, repository,
@ -1873,6 +1878,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
this, method, this, method,
methodName, methodName,
returnType.toString(), returnType.toString(),
containerType,
paramNames, paramNames,
paramTypes, paramTypes,
parameterNullability(method, entity), parameterNullability(method, entity),
@ -1894,7 +1900,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
this, method, this, method,
methodName, methodName,
returnType.toString(), returnType.toString(),
null, containerType,
paramNames, paramNames,
paramTypes, paramTypes,
parameterNullability(method, entity), parameterNullability(method, entity),

View File

@ -33,9 +33,9 @@ public class CriteriaDeleteMethod extends AbstractCriteriaMethod {
boolean addNonnullAnnotation, boolean addNonnullAnnotation,
boolean dataRepository, boolean dataRepository,
String fullReturnType) { String fullReturnType) {
super( annotationMetaEntity, method, methodName, entity, belongsToDao, sessionType, sessionName, emptyList(), super( annotationMetaEntity, method, methodName, entity, null, belongsToDao, sessionType,
paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, multivalued, paramPatterns, sessionName, emptyList(), paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository,
fullReturnType); multivalued, paramPatterns, fullReturnType);
this.paramNullability = paramNullability; this.paramNullability = paramNullability;
} }

View File

@ -16,7 +16,6 @@ import java.util.List;
*/ */
public class CriteriaFinderMethod extends AbstractCriteriaMethod { public class CriteriaFinderMethod extends AbstractCriteriaMethod {
private final @Nullable String containerType;
private final List<Boolean> paramNullability; private final List<Boolean> paramNullability;
CriteriaFinderMethod( CriteriaFinderMethod(
@ -36,10 +35,9 @@ public class CriteriaFinderMethod extends AbstractCriteriaMethod {
boolean addNonnullAnnotation, boolean addNonnullAnnotation,
boolean dataRepository, boolean dataRepository,
String fullReturnType) { String fullReturnType) {
super( annotationMetaEntity, method, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, super( annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName,
paramNames, paramTypes, orderBys, addNonnullAnnotation, dataRepository, multivalued, paramPatterns, fetchProfiles, paramNames, paramTypes, orderBys, addNonnullAnnotation, dataRepository, multivalued,
fullReturnType); paramPatterns, fullReturnType);
this.containerType = containerType;
this.paramNullability = paramNullability; this.paramNullability = paramNullability;
} }

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.processor.annotation; package org.hibernate.processor.annotation;
import org.checkerframework.checker.nullness.qual.Nullable;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import java.util.List; import java.util.List;
@ -24,6 +26,7 @@ public class IdFinderMethod extends AbstractFinderMethod {
AnnotationMetaEntity annotationMetaEntity, AnnotationMetaEntity annotationMetaEntity,
ExecutableElement method, ExecutableElement method,
String methodName, String entity, String methodName, String entity,
@Nullable String containerType, //must be null or Optional
List<String> paramNames, List<String> paramTypes, List<String> paramNames, List<String> paramTypes,
boolean belongsToDao, boolean belongsToDao,
String sessionType, String sessionType,
@ -32,8 +35,8 @@ public class IdFinderMethod extends AbstractFinderMethod {
boolean addNonnullAnnotation, boolean addNonnullAnnotation,
boolean dataRepository, boolean dataRepository,
String fullReturnType) { String fullReturnType) {
super( annotationMetaEntity, method, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, super( annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName,
paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType ); fetchProfiles, paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType );
int idParameter = idParameter(paramNames, paramTypes); int idParameter = idParameter(paramNames, paramTypes);
this.paramName = paramNames.get(idParameter); this.paramName = paramNames.get(idParameter);
this.paramType = paramTypes.get(idParameter); this.paramType = paramTypes.get(idParameter);
@ -81,7 +84,9 @@ public class IdFinderMethod extends AbstractFinderMethod {
} }
private void throwIfNull(StringBuilder declaration) { private void throwIfNull(StringBuilder declaration) {
if ( isUsingStatelessSession() ) { if ( containerType == null ) {
declaration
.append(";\n");
if (dataRepository) { if (dataRepository) {
declaration declaration
.append("\t\tif (_result == null) throw new ") .append("\t\tif (_result == null) throw new ")
@ -111,20 +116,26 @@ public class IdFinderMethod extends AbstractFinderMethod {
.append("\treturn _result;\n"); .append("\treturn _result;\n");
} }
} }
else {
declaration
.append(");\n");
}
} }
private void varOrReturn(StringBuilder declaration) { private void varOrReturn(StringBuilder declaration) {
if (dataRepository) { if (dataRepository) {
declaration declaration
.append("\ttry {\n"); .append("\ttry {\n\t");
} }
if ( isUsingStatelessSession() ) { if ( containerType == null ) {
declaration declaration
.append("\t\tvar _result = "); .append("\tvar _result = ");
} }
else { else {
declaration declaration
.append("\t\treturn "); .append("\treturn ")
.append(annotationMetaEntity.staticImport(containerType, "ofNullable"))
.append('(');
} }
declaration declaration
.append(sessionName); .append(sessionName);
@ -140,7 +151,7 @@ public class IdFinderMethod extends AbstractFinderMethod {
declaration declaration
.append("\t\t\t.load(") .append("\t\t\t.load(")
.append(paramName) .append(paramName)
.append(");\n"); .append(")");
} }
private void findWithNoFetchProfiles(StringBuilder declaration) { private void findWithNoFetchProfiles(StringBuilder declaration) {
@ -161,7 +172,7 @@ public class IdFinderMethod extends AbstractFinderMethod {
.append(')'); .append(')');
} }
declaration declaration
.append(");\n"); .append(")");
} }
private static void nullCheck(StringBuilder declaration, String parameterName) { private static void nullCheck(StringBuilder declaration, String parameterName) {

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.processor.annotation; package org.hibernate.processor.annotation;
import org.checkerframework.checker.nullness.qual.Nullable;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import java.util.List; import java.util.List;
@ -22,6 +24,7 @@ public class NaturalIdFinderMethod extends AbstractFinderMethod {
AnnotationMetaEntity annotationMetaEntity, AnnotationMetaEntity annotationMetaEntity,
ExecutableElement method, ExecutableElement method,
String methodName, String entity, String methodName, String entity,
@Nullable String containerType, //must be null or Optional
List<String> paramNames, List<String> paramTypes, List<String> paramNames, List<String> paramTypes,
List<Boolean> paramNullability, List<Boolean> paramNullability,
boolean belongsToDao, boolean belongsToDao,
@ -31,8 +34,8 @@ public class NaturalIdFinderMethod extends AbstractFinderMethod {
boolean addNonnullAnnotation, boolean addNonnullAnnotation,
boolean dataRepository, boolean dataRepository,
String fullReturnType) { String fullReturnType) {
super( annotationMetaEntity, method, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, super( annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName,
paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType ); fetchProfiles, paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType );
this.paramNullability = paramNullability; this.paramNullability = paramNullability;
} }
@ -85,9 +88,16 @@ public class NaturalIdFinderMethod extends AbstractFinderMethod {
.append(")\n"); .append(")\n");
} }
} }
if ( containerType == null ) {
//TODO we should probably throw if this returns null
declaration declaration
.append("\t\t\t.load();\n"); .append("\t\t\t.load();\n");
} }
else {
declaration
.append("\t\t\t.loadOptional();\n");
}
}
private void findReactively(StringBuilder declaration) { private void findReactively(StringBuilder declaration) {
boolean composite = isComposite(); boolean composite = isComposite();

View File

@ -8,6 +8,7 @@ import org.hibernate.annotations.processing.SQL;
import org.hibernate.query.SelectionQuery; import org.hibernate.query.SelectionQuery;
import java.util.List; import java.util.List;
import java.util.Optional;
public interface StatefulDao { public interface StatefulDao {
@ -16,12 +17,18 @@ public interface StatefulDao {
@Find @Find
Book getBook(String isbn); Book getBook(String isbn);
@Find
Optional<Book> getBookMaybe(String isbn);
@Find(enabledFetchProfiles="Goodbye") @Find(enabledFetchProfiles="Goodbye")
Book getBookFetching(String isbn); Book getBookFetching(String isbn);
@Find @Find
Book getBook(String title, String author); Book getBook(String title, String author);
@Find
Optional<Book> getBookMaybe(String title, String author);
@Find(enabledFetchProfiles="Hello") @Find(enabledFetchProfiles="Hello")
Book getBookFetching(String title, String author); Book getBookFetching(String title, String author);

View File

@ -8,6 +8,7 @@ import org.hibernate.annotations.processing.SQL;
import org.hibernate.query.SelectionQuery; import org.hibernate.query.SelectionQuery;
import java.util.List; import java.util.List;
import java.util.Optional;
public interface StatelessDao { public interface StatelessDao {
@ -16,12 +17,18 @@ public interface StatelessDao {
@Find @Find
Book getBook(String isbn); Book getBook(String isbn);
@Find
Optional<Book> getBookMaybe(String isbn);
@Find(enabledFetchProfiles="Goodbye") @Find(enabledFetchProfiles="Goodbye")
Book getBookFetching(String isbn); Book getBookFetching(String isbn);
@Find @Find
Book getBook(String title, String author); Book getBook(String title, String author);
@Find
Optional<Book> getBookMaybe(String title, String author);
@Find(enabledFetchProfiles="Hello") @Find(enabledFetchProfiles="Hello")
Book getBookFetching(String title, String author); Book getBookFetching(String title, String author);