allow @Find @Nullable and @Query @Nullable
to return null from a repository method Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
37195c21e1
commit
2a8fef4386
|
@ -1,5 +1,6 @@
|
|||
package org.hibernate.processor.test.data.basic;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.data.Limit;
|
||||
import jakarta.data.Order;
|
||||
import jakarta.data.Sort;
|
||||
|
@ -65,6 +66,9 @@ public interface BookAuthorRepository {
|
|||
@Find
|
||||
Optional<Book> bookIfAny(String isbn);
|
||||
|
||||
@Find @Nullable
|
||||
Book bookOrNullIfNone(String isbn);
|
||||
|
||||
@Find
|
||||
Author author(String ssn);
|
||||
|
||||
|
@ -116,6 +120,10 @@ public interface BookAuthorRepository {
|
|||
@Query("from Book where title = :title")
|
||||
Book bookWithTitle(String title);
|
||||
|
||||
@Nullable
|
||||
@Query("from Book where title = :title")
|
||||
Book bookWithTitleOrNullIfNone(String title);
|
||||
|
||||
@Query("from Book where title = :title")
|
||||
Optional<Book> bookWithTitleMaybe(String title);
|
||||
|
||||
|
|
|
@ -37,10 +37,11 @@ public abstract class AbstractCriteriaMethod extends AbstractFinderMethod {
|
|||
boolean convertToDataExceptions,
|
||||
List<Boolean> multivalued,
|
||||
List<Boolean> paramPatterns,
|
||||
String fullReturnType) {
|
||||
String fullReturnType,
|
||||
boolean nullable) {
|
||||
super(annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName,
|
||||
fetchProfiles, paramNames, paramTypes, orderBys, addNonnullAnnotation, convertToDataExceptions,
|
||||
fullReturnType);
|
||||
fullReturnType, nullable);
|
||||
this.multivalued = multivalued;
|
||||
this.paramPatterns = paramPatterns;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ public abstract class AbstractFinderMethod extends AbstractQueryMethod {
|
|||
List<OrderBy> orderBys,
|
||||
boolean addNonnullAnnotation,
|
||||
boolean convertToDataExceptions,
|
||||
String fullReturnType) {
|
||||
String fullReturnType,
|
||||
boolean nullable) {
|
||||
super( annotationMetaEntity, method,
|
||||
methodName,
|
||||
paramNames, paramTypes, entity,
|
||||
|
@ -47,7 +48,8 @@ public abstract class AbstractFinderMethod extends AbstractQueryMethod {
|
|||
belongsToDao, orderBys,
|
||||
addNonnullAnnotation,
|
||||
convertToDataExceptions,
|
||||
fullReturnType );
|
||||
fullReturnType,
|
||||
nullable );
|
||||
this.entity = entity;
|
||||
this.containerType = containerType;
|
||||
this.fetchProfiles = fetchProfiles;
|
||||
|
|
|
@ -50,6 +50,7 @@ public abstract class AbstractQueryMethod extends AbstractAnnotatedMethod {
|
|||
final boolean addNonnullAnnotation;
|
||||
final boolean dataRepository;
|
||||
final String fullReturnType;
|
||||
final boolean nullable;
|
||||
|
||||
AbstractQueryMethod(
|
||||
AnnotationMetaEntity annotationMetaEntity,
|
||||
|
@ -63,7 +64,8 @@ public abstract class AbstractQueryMethod extends AbstractAnnotatedMethod {
|
|||
List<OrderBy> orderBys,
|
||||
boolean addNonnullAnnotation,
|
||||
boolean dataRepository,
|
||||
String fullReturnType) {
|
||||
String fullReturnType,
|
||||
boolean nullable) {
|
||||
super(annotationMetaEntity, method, sessionName, sessionType);
|
||||
this.methodName = methodName;
|
||||
this.paramNames = paramNames;
|
||||
|
@ -74,6 +76,7 @@ public abstract class AbstractQueryMethod extends AbstractAnnotatedMethod {
|
|||
this.addNonnullAnnotation = addNonnullAnnotation;
|
||||
this.dataRepository = dataRepository;
|
||||
this.fullReturnType = fullReturnType;
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -580,14 +583,6 @@ public abstract class AbstractQueryMethod extends AbstractAnnotatedMethod {
|
|||
|| !orderBys.isEmpty();
|
||||
}
|
||||
|
||||
boolean unwrapIfNecessary(StringBuilder declaration, @Nullable String containerType, boolean unwrapped) {
|
||||
if ( OPTIONAL.equals(containerType) || isJakartaCursoredPage(containerType) ) {
|
||||
unwrapQuery( declaration, unwrapped );
|
||||
unwrapped = true;
|
||||
}
|
||||
return unwrapped;
|
||||
}
|
||||
|
||||
protected void executeSelect(
|
||||
StringBuilder declaration,
|
||||
List<String> paramTypes,
|
||||
|
@ -595,8 +590,15 @@ public abstract class AbstractQueryMethod extends AbstractAnnotatedMethod {
|
|||
boolean unwrapped,
|
||||
boolean mustUnwrap) {
|
||||
if ( containerType == null ) {
|
||||
declaration
|
||||
.append("\t\t\t.getSingleResult();");
|
||||
if ( nullable ) {
|
||||
unwrapQuery(declaration, unwrapped);
|
||||
declaration
|
||||
.append("\t\t\t.getSingleResultOrNull();");
|
||||
}
|
||||
else {
|
||||
declaration
|
||||
.append("\t\t\t.getSingleResult();");
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (containerType) {
|
||||
|
@ -612,6 +614,7 @@ public abstract class AbstractQueryMethod extends AbstractAnnotatedMethod {
|
|||
}
|
||||
break;
|
||||
case OPTIONAL:
|
||||
unwrapQuery(declaration, unwrapped);
|
||||
declaration
|
||||
.append("\t\t\t.uniqueResultOptional();");
|
||||
break;
|
||||
|
|
|
@ -1561,7 +1561,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
orderByList( method, entity ),
|
||||
context.addNonnullAnnotation(),
|
||||
jakartaDataRepository,
|
||||
fullReturnType(method)
|
||||
fullReturnType(method),
|
||||
hasAnnotation(method, NULLABLE)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1832,7 +1833,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
orderByList( method, entity ),
|
||||
context.addNonnullAnnotation(),
|
||||
jakartaDataRepository,
|
||||
fullReturnType(method)
|
||||
fullReturnType(method),
|
||||
hasAnnotation(method, NULLABLE)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1868,7 +1870,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
profiles,
|
||||
context.addNonnullAnnotation(),
|
||||
jakartaDataRepository,
|
||||
fullReturnType(method)
|
||||
fullReturnType(method),
|
||||
hasAnnotation(method, NULLABLE)
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
@ -1916,7 +1919,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
orderByList( method, entity ),
|
||||
context.addNonnullAnnotation(),
|
||||
jakartaDataRepository,
|
||||
fullReturnType(method)
|
||||
fullReturnType(method),
|
||||
hasAnnotation(method, NULLABLE)
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
@ -2275,7 +2279,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
orderBys,
|
||||
context.addNonnullAnnotation(),
|
||||
jakartaDataRepository,
|
||||
fullReturnType(method)
|
||||
fullReturnType(method),
|
||||
hasAnnotation(method, NULLABLE)
|
||||
);
|
||||
putMember( attribute.getPropertyName() + paramTypes, attribute );
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class CriteriaDeleteMethod extends AbstractCriteriaMethod {
|
|||
String fullReturnType) {
|
||||
super( annotationMetaEntity, method, methodName, entity, null, belongsToDao, sessionType,
|
||||
sessionName, emptyList(), paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository,
|
||||
multivalued, paramPatterns, fullReturnType);
|
||||
multivalued, paramPatterns, fullReturnType, false );
|
||||
this.paramNullability = paramNullability;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,10 +34,11 @@ public class CriteriaFinderMethod extends AbstractCriteriaMethod {
|
|||
List<OrderBy> orderBys,
|
||||
boolean addNonnullAnnotation,
|
||||
boolean dataRepository,
|
||||
String fullReturnType) {
|
||||
String fullReturnType,
|
||||
boolean nullable) {
|
||||
super( annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName,
|
||||
fetchProfiles, paramNames, paramTypes, orderBys, addNonnullAnnotation, dataRepository, multivalued,
|
||||
paramPatterns, fullReturnType);
|
||||
paramPatterns, fullReturnType, nullable );
|
||||
this.paramNullability = paramNullability;
|
||||
}
|
||||
|
||||
|
@ -60,7 +61,8 @@ public class CriteriaFinderMethod extends AbstractCriteriaMethod {
|
|||
castResult( declaration );
|
||||
createQuery( declaration );
|
||||
handlePageParameters( declaration, paramTypes, containerType );
|
||||
boolean unwrapped = specialNeeds( declaration );
|
||||
boolean unwrapped = !isUsingEntityManager();
|
||||
unwrapped = enableFetchProfile( declaration, unwrapped );
|
||||
unwrapped = applyOrder( declaration, paramTypes, containerType, unwrapped );
|
||||
execute( declaration, paramTypes, unwrapped );
|
||||
}
|
||||
|
@ -75,13 +77,6 @@ public class CriteriaFinderMethod extends AbstractCriteriaMethod {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean specialNeeds(StringBuilder declaration) {
|
||||
boolean unwrapped = !isUsingEntityManager();
|
||||
unwrapped = enableFetchProfile( declaration, unwrapped );
|
||||
unwrapped = unwrapIfNecessary( declaration, containerType, unwrapped );
|
||||
return unwrapped;
|
||||
}
|
||||
|
||||
private void execute(StringBuilder declaration, List<String> paramTypes, boolean unwrapped) {
|
||||
executeSelect( declaration, paramTypes, containerType, unwrapped, isHibernateQueryType(containerType) );
|
||||
}
|
||||
|
|
|
@ -34,9 +34,11 @@ public class IdFinderMethod extends AbstractFinderMethod {
|
|||
List<String> fetchProfiles,
|
||||
boolean addNonnullAnnotation,
|
||||
boolean dataRepository,
|
||||
String fullReturnType) {
|
||||
String fullReturnType,
|
||||
boolean nullable) {
|
||||
super( annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName,
|
||||
fetchProfiles, paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType );
|
||||
fetchProfiles, paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType,
|
||||
nullable );
|
||||
int idParameter = idParameter(paramNames, paramTypes);
|
||||
this.paramName = paramNames.get(idParameter);
|
||||
this.paramType = paramTypes.get(idParameter);
|
||||
|
@ -84,7 +86,11 @@ public class IdFinderMethod extends AbstractFinderMethod {
|
|||
}
|
||||
|
||||
private void throwIfNull(StringBuilder declaration) {
|
||||
if ( containerType == null ) {
|
||||
if (containerType != null) {
|
||||
declaration
|
||||
.append(')');
|
||||
}
|
||||
else if (!nullable) {
|
||||
declaration
|
||||
.append(";\n");
|
||||
if (dataRepository) {
|
||||
|
@ -102,7 +108,7 @@ public class IdFinderMethod extends AbstractFinderMethod {
|
|||
.append(", \"")
|
||||
.append(entity)
|
||||
.append("\"));\n")
|
||||
.append("\t\treturn _result;\n");
|
||||
.append("\t\treturn _result");
|
||||
}
|
||||
else {
|
||||
declaration
|
||||
|
@ -113,13 +119,11 @@ public class IdFinderMethod extends AbstractFinderMethod {
|
|||
.append(", \"")
|
||||
.append(entity)
|
||||
.append("\");\n")
|
||||
.append("\treturn _result;\n");
|
||||
.append("\treturn _result");
|
||||
}
|
||||
}
|
||||
else {
|
||||
declaration
|
||||
.append(");\n");
|
||||
}
|
||||
declaration
|
||||
.append(";\n");
|
||||
}
|
||||
|
||||
private void varOrReturn(StringBuilder declaration) {
|
||||
|
@ -127,15 +131,19 @@ public class IdFinderMethod extends AbstractFinderMethod {
|
|||
declaration
|
||||
.append("\ttry {\n\t");
|
||||
}
|
||||
if ( containerType == null ) {
|
||||
if (containerType != null) {
|
||||
declaration
|
||||
.append("\treturn ")
|
||||
.append(annotationMetaEntity.staticImport(containerType, "ofNullable"))
|
||||
.append('(');
|
||||
}
|
||||
else if (!nullable) {
|
||||
declaration
|
||||
.append("\tvar _result = ");
|
||||
}
|
||||
else {
|
||||
declaration
|
||||
.append("\treturn ")
|
||||
.append(annotationMetaEntity.staticImport(containerType, "ofNullable"))
|
||||
.append('(');
|
||||
.append("\treturn ");
|
||||
}
|
||||
declaration
|
||||
.append(sessionName);
|
||||
|
|
|
@ -35,7 +35,8 @@ public class NaturalIdFinderMethod extends AbstractFinderMethod {
|
|||
boolean dataRepository,
|
||||
String fullReturnType) {
|
||||
super( annotationMetaEntity, method, methodName, entity, containerType, belongsToDao, sessionType, sessionName,
|
||||
fetchProfiles, paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType );
|
||||
fetchProfiles, paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, fullReturnType,
|
||||
true );
|
||||
this.paramNullability = paramNullability;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,8 @@ public class QueryMethod extends AbstractQueryMethod {
|
|||
List<OrderBy> orderBys,
|
||||
boolean addNonnullAnnotation,
|
||||
boolean dataRepository,
|
||||
String fullReturnType) {
|
||||
String fullReturnType,
|
||||
boolean nullable) {
|
||||
super( annotationMetaEntity, method,
|
||||
methodName,
|
||||
paramNames, paramTypes, returnTypeName,
|
||||
|
@ -55,7 +56,8 @@ public class QueryMethod extends AbstractQueryMethod {
|
|||
belongsToDao, orderBys,
|
||||
addNonnullAnnotation,
|
||||
dataRepository,
|
||||
fullReturnType );
|
||||
fullReturnType,
|
||||
nullable );
|
||||
this.queryString = queryString;
|
||||
this.returnTypeClass = returnTypeClass;
|
||||
this.containerType = containerType;
|
||||
|
@ -97,7 +99,7 @@ public class QueryMethod extends AbstractQueryMethod {
|
|||
createQuery( declaration );
|
||||
setParameters( declaration, paramTypes, "");
|
||||
handlePageParameters( declaration, paramTypes, containerType );
|
||||
boolean unwrapped = specialNeeds( declaration );
|
||||
boolean unwrapped = !isUsingEntityManager();
|
||||
unwrapped = applyOrder( declaration, paramTypes, containerType, unwrapped );
|
||||
execute( declaration, unwrapped );
|
||||
convertExceptions( declaration );
|
||||
|
@ -106,12 +108,6 @@ public class QueryMethod extends AbstractQueryMethod {
|
|||
return declaration.toString();
|
||||
}
|
||||
|
||||
private boolean specialNeeds(StringBuilder declaration) {
|
||||
boolean unwrapped = !isUsingEntityManager();
|
||||
unwrapped = unwrapIfNecessary( declaration, containerType, unwrapped );
|
||||
return unwrapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
void createQuery(StringBuilder declaration) {
|
||||
declaration
|
||||
|
|
|
@ -130,6 +130,8 @@ public final class Constants {
|
|||
public static final String OPTIONAL = "java.util.Optional";
|
||||
public static final String STREAM = "java.util.stream.Stream";
|
||||
|
||||
public static final String NULLABLE = "jakarta.annotation.Nullable";
|
||||
|
||||
public static final String PANACHE_ORM_REPOSITORY_BASE = "io.quarkus.hibernate.orm.panache.PanacheRepositoryBase";
|
||||
public static final String PANACHE_ORM_ENTITY_BASE = "io.quarkus.hibernate.orm.panache.PanacheEntityBase";
|
||||
public static final String PANACHE_REACTIVE_REPOSITORY_BASE = "io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase";
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.hibernate.processor.test.dao;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.processing.Find;
|
||||
|
@ -17,6 +18,9 @@ public interface StatefulDao {
|
|||
@Find
|
||||
Book getBook(String isbn);
|
||||
|
||||
@Find @Nullable
|
||||
Book getBookOrNull(String isbn);
|
||||
|
||||
@Find
|
||||
Optional<Book> getBookMaybe(String isbn);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.hibernate.processor.test.dao;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import org.hibernate.StatelessSession;
|
||||
import org.hibernate.annotations.processing.Find;
|
||||
|
@ -26,6 +27,9 @@ public interface StatelessDao {
|
|||
@Find
|
||||
Book getBook(String title, String author);
|
||||
|
||||
@Find @Nullable
|
||||
Book getBookOrNull(String isbn);
|
||||
|
||||
@Find
|
||||
Optional<Book> getBookMaybe(String title, String author);
|
||||
|
||||
|
|
Loading…
Reference in New Issue