allow @Query methods to return array
This commit is contained in:
parent
813ae8ed9d
commit
4bb5bc60e9
|
@ -107,8 +107,14 @@ public interface BookAuthorRepository {
|
||||||
@Query("from Book where title like :title")
|
@Query("from Book where title like :title")
|
||||||
List<Book> books3(String title, Limit limit, Sort<Book>... order);
|
List<Book> books3(String title, Limit limit, Sort<Book>... order);
|
||||||
|
|
||||||
|
@Query("from Book where title like :title")
|
||||||
|
Book[] books4(String title, Sort<Book> sort);
|
||||||
|
|
||||||
@Query("select title from Book where title like :title order by isbn")
|
@Query("select title from Book where title like :title order by isbn")
|
||||||
Stream<String> titles(String title);
|
Stream<String> titles0(String title);
|
||||||
|
|
||||||
|
@Query("select title from Book where title like :title order by isbn")
|
||||||
|
String[] titles1(String title);
|
||||||
|
|
||||||
@Query("from Book")
|
@Query("from Book")
|
||||||
List<Book> everyBook1(PageRequest<? super Book> pageRequest);
|
List<Book> everyBook1(PageRequest<? super Book> pageRequest);
|
||||||
|
|
|
@ -139,7 +139,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
/**
|
/**
|
||||||
* The type of the "session getter" method of a DAO-style repository.
|
* The type of the "session getter" method of a DAO-style repository.
|
||||||
*/
|
*/
|
||||||
private String sessionType = Constants.ENTITY_MANAGER;
|
private String sessionType = ENTITY_MANAGER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The field or method call to obtain the session
|
* The field or method call to obtain the session
|
||||||
|
@ -456,35 +456,42 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPanacheType(TypeElement type) {
|
private boolean isPanacheType(TypeElement type) {
|
||||||
return isOrmPanacheType( type ) || isReactivePanacheType( type );
|
return isOrmPanacheType( type )
|
||||||
|
|| isReactivePanacheType( type );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isOrmPanacheType(TypeElement type) {
|
private boolean isOrmPanacheType(TypeElement type) {
|
||||||
ProcessingEnvironment processingEnvironment = this.context.getProcessingEnvironment();
|
final ProcessingEnvironment processingEnvironment = context.getProcessingEnvironment();
|
||||||
TypeElement panacheRepositorySuperType = processingEnvironment.getElementUtils().getTypeElement( Constants.PANACHE_ORM_REPOSITORY_BASE );
|
final Elements elements = processingEnvironment.getElementUtils();
|
||||||
TypeElement panacheEntitySuperType = processingEnvironment.getElementUtils().getTypeElement( Constants.PANACHE_ORM_ENTITY_BASE );
|
final TypeElement panacheRepositorySuperType = elements.getTypeElement( PANACHE_ORM_REPOSITORY_BASE );
|
||||||
|
final TypeElement panacheEntitySuperType = elements.getTypeElement( PANACHE_ORM_ENTITY_BASE );
|
||||||
if ( panacheRepositorySuperType == null || panacheEntitySuperType == null ) {
|
if ( panacheRepositorySuperType == null || panacheEntitySuperType == null ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Types types = processingEnvironment.getTypeUtils();
|
else {
|
||||||
// check against a raw supertype of PanacheRepositoryBase, which .asType() is not
|
final Types types = processingEnvironment.getTypeUtils();
|
||||||
return processingEnvironment.getTypeUtils().isSubtype( type.asType(), types.getDeclaredType( panacheRepositorySuperType ) )
|
|
||||||
|| processingEnvironment.getTypeUtils().isSubtype( type.asType(), panacheEntitySuperType.asType() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isReactivePanacheType(TypeElement type) {
|
|
||||||
ProcessingEnvironment processingEnvironment = this.context.getProcessingEnvironment();
|
|
||||||
TypeElement panacheRepositorySuperType = processingEnvironment.getElementUtils().getTypeElement( Constants.PANACHE_REACTIVE_REPOSITORY_BASE );
|
|
||||||
TypeElement panacheEntitySuperType = processingEnvironment.getElementUtils().getTypeElement( Constants.PANACHE_REACTIVE_ENTITY_BASE );
|
|
||||||
|
|
||||||
if ( panacheRepositorySuperType == null || panacheEntitySuperType == null ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Types types = processingEnvironment.getTypeUtils();
|
|
||||||
// check against a raw supertype of PanacheRepositoryBase, which .asType() is not
|
// check against a raw supertype of PanacheRepositoryBase, which .asType() is not
|
||||||
return types.isSubtype( type.asType(), types.getDeclaredType( panacheRepositorySuperType ) )
|
return types.isSubtype( type.asType(), types.getDeclaredType( panacheRepositorySuperType ) )
|
||||||
|| types.isSubtype( type.asType(), panacheEntitySuperType.asType() );
|
|| types.isSubtype( type.asType(), panacheEntitySuperType.asType() );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isReactivePanacheType(TypeElement type) {
|
||||||
|
final ProcessingEnvironment processingEnvironment = context.getProcessingEnvironment();
|
||||||
|
final Elements elements = processingEnvironment.getElementUtils();
|
||||||
|
final TypeElement panacheRepositorySuperType = elements.getTypeElement( PANACHE_REACTIVE_REPOSITORY_BASE );
|
||||||
|
final TypeElement panacheEntitySuperType = elements.getTypeElement( PANACHE_REACTIVE_ENTITY_BASE );
|
||||||
|
|
||||||
|
if ( panacheRepositorySuperType == null || panacheEntitySuperType == null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final Types types = processingEnvironment.getTypeUtils();
|
||||||
|
// check against a raw supertype of PanacheRepositoryBase, which .asType() is not
|
||||||
|
return types.isSubtype( type.asType(), types.getDeclaredType( panacheRepositorySuperType ) )
|
||||||
|
|| types.isSubtype( type.asType(), panacheEntitySuperType.asType() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there is a session getter method, we generate an instance
|
* If there is a session getter method, we generate an instance
|
||||||
|
@ -546,7 +553,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return Constants.ENTITY_MANAGER;
|
return ENTITY_MANAGER;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
importType( Constants.QUARKUS_SESSION_OPERATIONS );
|
importType( Constants.QUARKUS_SESSION_OPERATIONS );
|
||||||
|
@ -570,10 +577,10 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
if ( element.getKind() == ElementKind.INTERFACE ) {
|
if ( element.getKind() == ElementKind.INTERFACE ) {
|
||||||
final TypeElement typeElement = (TypeElement) element;
|
final TypeElement typeElement = (TypeElement) element;
|
||||||
final Name name = typeElement.getQualifiedName();
|
final Name name = typeElement.getQualifiedName();
|
||||||
return name.contentEquals(Constants.HIB_SESSION)
|
return name.contentEquals(HIB_SESSION)
|
||||||
|| name.contentEquals(Constants.HIB_STATELESS_SESSION)
|
|| name.contentEquals(HIB_STATELESS_SESSION)
|
||||||
|| name.contentEquals(Constants.MUTINY_SESSION)
|
|| name.contentEquals(MUTINY_SESSION)
|
||||||
|| name.contentEquals(Constants.ENTITY_MANAGER);
|
|| name.contentEquals(ENTITY_MANAGER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -655,7 +662,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
private boolean isPersistent(Element memberOfClass, AccessType membersKind) {
|
private boolean isPersistent(Element memberOfClass, AccessType membersKind) {
|
||||||
return ( entityAccessTypeInfo.getAccessType() == membersKind
|
return ( entityAccessTypeInfo.getAccessType() == membersKind
|
||||||
|| determineAnnotationSpecifiedAccessType( memberOfClass ) != null )
|
|| determineAnnotationSpecifiedAccessType( memberOfClass ) != null )
|
||||||
&& !containsAnnotation( memberOfClass, Constants.TRANSIENT )
|
&& !containsAnnotation( memberOfClass, TRANSIENT )
|
||||||
&& !memberOfClass.getModifiers().contains( Modifier.TRANSIENT )
|
&& !memberOfClass.getModifiers().contains( Modifier.TRANSIENT )
|
||||||
&& !memberOfClass.getModifiers().contains( Modifier.STATIC )
|
&& !memberOfClass.getModifiers().contains( Modifier.STATIC )
|
||||||
&& !( memberOfClass.getKind() == ElementKind.METHOD
|
&& !( memberOfClass.getKind() == ElementKind.METHOD
|
||||||
|
@ -1591,25 +1598,63 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
@Nullable TypeElement containerType,
|
@Nullable TypeElement containerType,
|
||||||
AnnotationMirror mirror,
|
AnnotationMirror mirror,
|
||||||
boolean isNative) {
|
boolean isNative) {
|
||||||
|
|
||||||
final AnnotationValue value = getAnnotationValueRef( mirror, "value" );
|
final AnnotationValue value = getAnnotationValueRef( mirror, "value" );
|
||||||
if ( value != null ) {
|
if ( value != null ) {
|
||||||
final Object query = value.getValue();
|
final Object query = value.getValue();
|
||||||
if ( query instanceof String ) {
|
if ( query instanceof String ) {
|
||||||
final String queryString = (String) query;
|
final String queryString = (String) query;
|
||||||
|
|
||||||
|
// The following is quite fragile!
|
||||||
|
final String containerTypeName;
|
||||||
|
if ( containerType == null ) {
|
||||||
|
if ( returnType != null && returnType.getKind() == TypeKind.ARRAY ) {
|
||||||
|
final ArrayType arrayType = (ArrayType) returnType;
|
||||||
|
final TypeMirror componentType = arrayType.getComponentType();
|
||||||
|
final TypeElement object = context.getElementUtils().getTypeElement(JAVA_OBJECT);
|
||||||
|
if ( !context.getTypeUtils().isSameType( object.asType(), componentType ) ) {
|
||||||
|
returnType = componentType;
|
||||||
|
containerTypeName = "[]";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// assume it's returning a single tuple as Object[]
|
||||||
|
containerTypeName = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
containerTypeName = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
containerTypeName = containerType.getQualifiedName().toString();
|
||||||
|
}
|
||||||
|
|
||||||
final List<String> paramNames = parameterNames( method );
|
final List<String> paramNames = parameterNames( method );
|
||||||
final List<String> paramTypes = parameterTypes( method );
|
final List<String> paramTypes = parameterTypes( method );
|
||||||
|
|
||||||
|
if ( isNative ) {
|
||||||
|
validateSql( method, mirror, queryString, paramNames, value );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
validateHql( method, returnType, mirror, value, queryString, paramNames, paramTypes );
|
||||||
|
}
|
||||||
|
|
||||||
|
// now check that the query has a parameter for every method parameter
|
||||||
|
checkParameters( method, returnType, paramNames, paramTypes, mirror, value, queryString );
|
||||||
|
|
||||||
final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes );
|
final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes );
|
||||||
final DeclaredType resultType = resultType( method, returnType, mirror, value );
|
final DeclaredType resultType = resultType( method, returnType, mirror, value );
|
||||||
final List<OrderBy> orderBys = resultType == null
|
final List<OrderBy> orderBys = resultType == null
|
||||||
? emptyList()
|
? emptyList()
|
||||||
: orderByList( method, (TypeElement) resultType.asElement() );
|
: orderByList( method, (TypeElement) resultType.asElement() );
|
||||||
|
|
||||||
final QueryMethod attribute =
|
final QueryMethod attribute =
|
||||||
new QueryMethod(
|
new QueryMethod(
|
||||||
this,
|
this,
|
||||||
method.getSimpleName().toString(),
|
method.getSimpleName().toString(),
|
||||||
queryString,
|
queryString,
|
||||||
returnType == null ? null : returnType.toString(),
|
returnType == null ? null : returnType.toString(),
|
||||||
containerType == null ? null : containerType.getQualifiedName().toString(),
|
containerTypeName,
|
||||||
paramNames,
|
paramNames,
|
||||||
paramTypes,
|
paramTypes,
|
||||||
isInsertUpdateDelete( queryString ),
|
isInsertUpdateDelete( queryString ),
|
||||||
|
@ -1622,16 +1667,6 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
jakartaDataRepository
|
jakartaDataRepository
|
||||||
);
|
);
|
||||||
putMember( attribute.getPropertyName() + paramTypes, attribute );
|
putMember( attribute.getPropertyName() + paramTypes, attribute );
|
||||||
|
|
||||||
if ( isNative ) {
|
|
||||||
validateSql( method, mirror, queryString, paramNames, value );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
validateHql( method, returnType, mirror, value, queryString, paramNames, paramTypes );
|
|
||||||
}
|
|
||||||
|
|
||||||
// now check that the query has a parameter for every method parameter
|
|
||||||
checkParameters( method, returnType, paramNames, paramTypes, mirror, value, queryString );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1710,9 +1745,9 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
if ( reactive ) {
|
if ( reactive ) {
|
||||||
// for reactive calls, don't use the returnType param, which has been ununi-ed, we want to check the full one
|
// for reactive calls, don't use the returnType param, which has been ununi-ed, we want to check the full one
|
||||||
final String returnTypeName = method.getReturnType().toString();
|
final String returnTypeName = method.getReturnType().toString();
|
||||||
return returnTypeName.equals( Constants.UNI_VOID )
|
return returnTypeName.equals( UNI_VOID )
|
||||||
|| returnTypeName.equals( Constants.UNI_BOOLEAN )
|
|| returnTypeName.equals( UNI_BOOLEAN )
|
||||||
|| returnTypeName.equals( Constants.UNI_INTEGER );
|
|| returnTypeName.equals( UNI_INTEGER );
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1833,9 +1868,9 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
}
|
}
|
||||||
final TypeElement typeElement = (TypeElement) returnType.asElement();
|
final TypeElement typeElement = (TypeElement) returnType.asElement();
|
||||||
final Name qualifiedName = typeElement.getQualifiedName();
|
final Name qualifiedName = typeElement.getQualifiedName();
|
||||||
if ( qualifiedName.contentEquals(Constants.TUPLE)
|
if ( qualifiedName.contentEquals(TUPLE)
|
||||||
|| qualifiedName.contentEquals(Constants.LIST)
|
|| qualifiedName.contentEquals(LIST)
|
||||||
|| qualifiedName.contentEquals(Constants.MAP) ) {
|
|| qualifiedName.contentEquals(MAP) ) {
|
||||||
// these are exceptionally allowed
|
// these are exceptionally allowed
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1903,7 +1938,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
if ( componentType.getKind() == TypeKind.DECLARED ) {
|
if ( componentType.getKind() == TypeKind.DECLARED ) {
|
||||||
final DeclaredType declaredType = (DeclaredType) componentType;
|
final DeclaredType declaredType = (DeclaredType) componentType;
|
||||||
final TypeElement typeElement = (TypeElement) declaredType.asElement();
|
final TypeElement typeElement = (TypeElement) declaredType.asElement();
|
||||||
return typeElement.getQualifiedName().contentEquals(Constants.JAVA_OBJECT);
|
return typeElement.getQualifiedName().contentEquals(JAVA_OBJECT);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2114,11 +2149,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean usingReactiveSession(String sessionType) {
|
private boolean usingReactiveSession(String sessionType) {
|
||||||
return Constants.MUTINY_SESSION.equals(sessionType)
|
return MUTINY_SESSION.equals(sessionType)
|
||||||
|| Constants.UNI_MUTINY_SESSION.equals(sessionType);
|
|| Constants.UNI_MUTINY_SESSION.equals(sessionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean usingStatelessSession(String sessionType) {
|
private boolean usingStatelessSession(String sessionType) {
|
||||||
return Constants.HIB_STATELESS_SESSION.equals(sessionType);
|
return HIB_STATELESS_SESSION.equals(sessionType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.processor.annotation;
|
package org.hibernate.processor.annotation;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.processor.util.Constants;
|
import org.hibernate.processor.util.Constants;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -199,6 +200,7 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
|
||||||
.append(".in(");
|
.append(".in(");
|
||||||
if ( paramType.endsWith("[]") ) {
|
if ( paramType.endsWith("[]") ) {
|
||||||
declaration
|
declaration
|
||||||
|
.append("(Object[]) ")
|
||||||
//TODO: only safe if we are binding literals as parameters!!!
|
//TODO: only safe if we are binding literals as parameters!!!
|
||||||
.append(parameterName);
|
.append(parameterName);
|
||||||
|
|
||||||
|
@ -247,7 +249,10 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
|
||||||
private StringBuilder returnType() {
|
private StringBuilder returnType() {
|
||||||
final StringBuilder type = new StringBuilder();
|
final StringBuilder type = new StringBuilder();
|
||||||
if ( "[]".equals(containerType) ) {
|
if ( "[]".equals(containerType) ) {
|
||||||
type.append(returnTypeName).append("[]");
|
if ( returnTypeName == null ) {
|
||||||
|
throw new AssertionFailure("array return type, but no type name");
|
||||||
|
}
|
||||||
|
type.append(annotationMetaEntity.importType(returnTypeName)).append("[]");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
boolean returnsUni = isReactive()
|
boolean returnsUni = isReactive()
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.processor.annotation;
|
package org.hibernate.processor.annotation;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.processor.util.Constants;
|
import org.hibernate.processor.util.Constants;
|
||||||
|
|
||||||
|
@ -192,7 +193,14 @@ public class QueryMethod extends AbstractQueryMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
private StringBuilder returnType() {
|
private StringBuilder returnType() {
|
||||||
StringBuilder type = new StringBuilder();
|
final StringBuilder type = new StringBuilder();
|
||||||
|
if ( "[]".equals(containerType) ) {
|
||||||
|
if ( returnTypeName == null ) {
|
||||||
|
throw new AssertionFailure("array return type, but no type name");
|
||||||
|
}
|
||||||
|
type.append(annotationMetaEntity.importType(returnTypeName)).append("[]");
|
||||||
|
}
|
||||||
|
else {
|
||||||
boolean returnsUni = isReactive()
|
boolean returnsUni = isReactive()
|
||||||
&& (containerType == null || LIST.equals(containerType));
|
&& (containerType == null || LIST.equals(containerType));
|
||||||
if ( returnsUni ) {
|
if ( returnsUni ) {
|
||||||
|
@ -210,6 +218,7 @@ public class QueryMethod extends AbstractQueryMethod {
|
||||||
if ( returnsUni ) {
|
if ( returnsUni ) {
|
||||||
type.append('>');
|
type.append('>');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,9 @@ public interface Dao {
|
||||||
@HQL("order by isbn asc, publicationDate desc")
|
@HQL("order by isbn asc, publicationDate desc")
|
||||||
List<Book> allBooks();
|
List<Book> allBooks();
|
||||||
|
|
||||||
|
@HQL("order by isbn asc, publicationDate desc")
|
||||||
|
Book[] allBooksAsArray();
|
||||||
|
|
||||||
@SQL("select * from Book where isbn = :isbn")
|
@SQL("select * from Book where isbn = :isbn")
|
||||||
Book findByIsbnNative(String isbn);
|
Book findByIsbnNative(String isbn);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue