diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/basic/BookAuthorRepository.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/basic/BookAuthorRepository.java index df2b563c8d..5145250732 100644 --- a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/basic/BookAuthorRepository.java +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/basic/BookAuthorRepository.java @@ -74,6 +74,9 @@ public interface BookAuthorRepository { @Find Book byTitleAndDate(String title, LocalDate publicationDate); + @Find + Optional maybeByTitleAndDate(String title, LocalDate publicationDate); + @Find Book bookById(@By("isbn") String id); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java index dd389f31eb..564026c7bc 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java @@ -6,6 +6,8 @@ */ package org.hibernate.processor.annotation; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.lang.model.element.ExecutableElement; import java.util.List; import java.util.StringTokenizer; @@ -24,6 +26,7 @@ public abstract class AbstractCriteriaMethod extends AbstractFinderMethod { AnnotationMetaEntity annotationMetaEntity, ExecutableElement method, String methodName, String entity, + @Nullable String containerType, boolean belongsToDao, String sessionType, String sessionName, List fetchProfiles, @@ -35,8 +38,9 @@ public abstract class AbstractCriteriaMethod extends AbstractFinderMethod { List multivalued, List paramPatterns, String fullReturnType) { - super(annotationMetaEntity, method, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, - paramNames, paramTypes, orderBys, addNonnullAnnotation, convertToDataExceptions, fullReturnType); + super(annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName, + fetchProfiles, paramNames, paramTypes, orderBys, addNonnullAnnotation, convertToDataExceptions, + fullReturnType); this.multivalued = multivalued; this.paramPatterns = paramPatterns; } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractFinderMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractFinderMethod.java index c7c208c42f..bc3b58f290 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractFinderMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractFinderMethod.java @@ -6,6 +6,7 @@ */ package org.hibernate.processor.annotation; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.internal.util.StringHelper; import javax.lang.model.element.ExecutableElement; @@ -19,6 +20,7 @@ import static org.hibernate.processor.util.StringUtil.getUpperUnderscoreCaseFrom * @author Gavin King */ public abstract class AbstractFinderMethod extends AbstractQueryMethod { + final @Nullable String containerType; final String entity; final List fetchProfiles; @@ -27,6 +29,7 @@ public abstract class AbstractFinderMethod extends AbstractQueryMethod { ExecutableElement method, String methodName, String entity, + @Nullable String containerType, boolean belongsToDao, String sessionType, String sessionName, @@ -46,6 +49,7 @@ public abstract class AbstractFinderMethod extends AbstractQueryMethod { convertToDataExceptions, fullReturnType ); this.entity = entity; + this.containerType = containerType; this.fetchProfiles = fetchProfiles; } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java index 165fbd03e2..4fff9c9d78 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java @@ -1482,9 +1482,9 @@ public class AnnotationMetaEntity extends AnnotationMeta { Diagnostic.Kind.ERROR ); } else { - if ( containerType != null ) { + if ( containerType != null + && !containerType.getQualifiedName().contentEquals(OPTIONAL) ) { // 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 ); } else { @@ -1497,6 +1497,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { message( parameter, "ordering would have no effect", Diagnostic.Kind.ERROR); } } + final String containerTypeName = containerType==null ? null : OPTIONAL; final long parameterCount = method.getParameters().stream() .filter(AnnotationMetaEntity::isFinderParameterMappingToAttribute) @@ -1506,10 +1507,10 @@ public class AnnotationMetaEntity extends AnnotationMeta { message( method, "missing parameter", Diagnostic.Kind.ERROR ); break; case 1: - createSingleParameterFinder( method, declaredType, entity ); + createSingleParameterFinder( method, declaredType, entity, containerTypeName ); break; 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 List paramNames = parameterNames( method, entity ); final List paramTypes = parameterTypes( method ); @@ -1796,6 +1798,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { this, method, methodName, returnType.toString(), + containerType, paramNames, paramTypes, parameterNullability(method, entity), @@ -1816,7 +1819,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { this, method, methodName, returnType.toString(), - null, + containerType, paramNames, paramTypes, 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 VariableElement parameter = method.getParameters().stream() @@ -1855,6 +1859,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { this, method, methodName, returnType.toString(), + containerType, paramNames, paramTypes, repository, @@ -1873,6 +1878,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { this, method, methodName, returnType.toString(), + containerType, paramNames, paramTypes, parameterNullability(method, entity), @@ -1894,7 +1900,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { this, method, methodName, returnType.toString(), - null, + containerType, paramNames, paramTypes, parameterNullability(method, entity), diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaDeleteMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaDeleteMethod.java index b40cb93a5a..542d62ce96 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaDeleteMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaDeleteMethod.java @@ -33,9 +33,9 @@ public class CriteriaDeleteMethod extends AbstractCriteriaMethod { boolean addNonnullAnnotation, boolean dataRepository, String fullReturnType) { - super( annotationMetaEntity, method, methodName, entity, belongsToDao, sessionType, sessionName, emptyList(), - paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, multivalued, paramPatterns, - fullReturnType); + super( annotationMetaEntity, method, methodName, entity, null, belongsToDao, sessionType, + sessionName, emptyList(), paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, + multivalued, paramPatterns, fullReturnType); this.paramNullability = paramNullability; } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java index 1b609c1646..a5c99b4d7e 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java @@ -16,7 +16,6 @@ import java.util.List; */ public class CriteriaFinderMethod extends AbstractCriteriaMethod { - private final @Nullable String containerType; private final List paramNullability; CriteriaFinderMethod( @@ -36,10 +35,9 @@ public class CriteriaFinderMethod extends AbstractCriteriaMethod { boolean addNonnullAnnotation, boolean dataRepository, String fullReturnType) { - super( annotationMetaEntity, method, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, - paramNames, paramTypes, orderBys, addNonnullAnnotation, dataRepository, multivalued, paramPatterns, - fullReturnType); - this.containerType = containerType; + super( annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName, + fetchProfiles, paramNames, paramTypes, orderBys, addNonnullAnnotation, dataRepository, multivalued, + paramPatterns, fullReturnType); this.paramNullability = paramNullability; } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/IdFinderMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/IdFinderMethod.java index d926c1ae1a..f12404ba8d 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/IdFinderMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/IdFinderMethod.java @@ -6,6 +6,8 @@ */ package org.hibernate.processor.annotation; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.lang.model.element.ExecutableElement; import java.util.List; @@ -24,6 +26,7 @@ public class IdFinderMethod extends AbstractFinderMethod { AnnotationMetaEntity annotationMetaEntity, ExecutableElement method, String methodName, String entity, + @Nullable String containerType, //must be null or Optional List paramNames, List paramTypes, boolean belongsToDao, String sessionType, @@ -32,8 +35,8 @@ public class IdFinderMethod extends AbstractFinderMethod { boolean addNonnullAnnotation, boolean dataRepository, String fullReturnType) { - super( annotationMetaEntity, method, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, - paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType ); + super( annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName, + fetchProfiles, paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType ); int idParameter = idParameter(paramNames, paramTypes); this.paramName = paramNames.get(idParameter); this.paramType = paramTypes.get(idParameter); @@ -81,7 +84,9 @@ public class IdFinderMethod extends AbstractFinderMethod { } private void throwIfNull(StringBuilder declaration) { - if ( isUsingStatelessSession() ) { + if ( containerType == null ) { + declaration + .append(";\n"); if (dataRepository) { declaration .append("\t\tif (_result == null) throw new ") @@ -111,20 +116,26 @@ public class IdFinderMethod extends AbstractFinderMethod { .append("\treturn _result;\n"); } } + else { + declaration + .append(");\n"); + } } private void varOrReturn(StringBuilder declaration) { if (dataRepository) { declaration - .append("\ttry {\n"); + .append("\ttry {\n\t"); } - if ( isUsingStatelessSession() ) { + if ( containerType == null ) { declaration - .append("\t\tvar _result = "); + .append("\tvar _result = "); } else { declaration - .append("\t\treturn "); + .append("\treturn ") + .append(annotationMetaEntity.staticImport(containerType, "ofNullable")) + .append('('); } declaration .append(sessionName); @@ -140,7 +151,7 @@ public class IdFinderMethod extends AbstractFinderMethod { declaration .append("\t\t\t.load(") .append(paramName) - .append(");\n"); + .append(")"); } private void findWithNoFetchProfiles(StringBuilder declaration) { @@ -161,7 +172,7 @@ public class IdFinderMethod extends AbstractFinderMethod { .append(')'); } declaration - .append(");\n"); + .append(")"); } private static void nullCheck(StringBuilder declaration, String parameterName) { diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/NaturalIdFinderMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/NaturalIdFinderMethod.java index 6124969505..e8e960a444 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/NaturalIdFinderMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/NaturalIdFinderMethod.java @@ -6,6 +6,8 @@ */ package org.hibernate.processor.annotation; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.lang.model.element.ExecutableElement; import java.util.List; @@ -22,6 +24,7 @@ public class NaturalIdFinderMethod extends AbstractFinderMethod { AnnotationMetaEntity annotationMetaEntity, ExecutableElement method, String methodName, String entity, + @Nullable String containerType, //must be null or Optional List paramNames, List paramTypes, List paramNullability, boolean belongsToDao, @@ -31,8 +34,8 @@ public class NaturalIdFinderMethod extends AbstractFinderMethod { boolean addNonnullAnnotation, boolean dataRepository, String fullReturnType) { - super( annotationMetaEntity, method, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, - paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType ); + super( annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName, + fetchProfiles, paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType ); this.paramNullability = paramNullability; } @@ -85,8 +88,15 @@ public class NaturalIdFinderMethod extends AbstractFinderMethod { .append(")\n"); } } - declaration - .append("\t\t\t.load();\n"); + if ( containerType == null ) { + //TODO we should probably throw if this returns null + declaration + .append("\t\t\t.load();\n"); + } + else { + declaration + .append("\t\t\t.loadOptional();\n"); + } } private void findReactively(StringBuilder declaration) { diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/dao/StatefulDao.java b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/dao/StatefulDao.java index 2937591140..70f2347dbd 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/dao/StatefulDao.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/dao/StatefulDao.java @@ -8,6 +8,7 @@ import org.hibernate.annotations.processing.SQL; import org.hibernate.query.SelectionQuery; import java.util.List; +import java.util.Optional; public interface StatefulDao { @@ -16,12 +17,18 @@ public interface StatefulDao { @Find Book getBook(String isbn); + @Find + Optional getBookMaybe(String isbn); + @Find(enabledFetchProfiles="Goodbye") Book getBookFetching(String isbn); @Find Book getBook(String title, String author); + @Find + Optional getBookMaybe(String title, String author); + @Find(enabledFetchProfiles="Hello") Book getBookFetching(String title, String author); diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/dao/StatelessDao.java b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/dao/StatelessDao.java index d31f31733d..53517a598b 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/dao/StatelessDao.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/dao/StatelessDao.java @@ -8,6 +8,7 @@ import org.hibernate.annotations.processing.SQL; import org.hibernate.query.SelectionQuery; import java.util.List; +import java.util.Optional; public interface StatelessDao { @@ -16,12 +17,18 @@ public interface StatelessDao { @Find Book getBook(String isbn); + @Find + Optional getBookMaybe(String isbn); + @Find(enabledFetchProfiles="Goodbye") Book getBookFetching(String isbn); @Find Book getBook(String title, String author); + @Find + Optional getBookMaybe(String title, String author); + @Find(enabledFetchProfiles="Hello") Book getBookFetching(String title, String author);