diff --git a/src/main/java/org/springframework/data/repository/query/QueryMethod.java b/src/main/java/org/springframework/data/repository/query/QueryMethod.java index f1c704f3a..232fec299 100644 --- a/src/main/java/org/springframework/data/repository/query/QueryMethod.java +++ b/src/main/java/org/springframework/data/repository/query/QueryMethod.java @@ -26,6 +26,8 @@ import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; import org.springframework.data.repository.core.EntityMetadata; import org.springframework.data.repository.core.RepositoryMetadata; +import org.springframework.data.repository.util.QueryExecutionConverters; +import org.springframework.data.util.ClassTypeInformation; import org.springframework.util.Assert; /** @@ -33,11 +35,13 @@ import org.springframework.util.Assert; * with specific information that is necessary to construct {@link RepositoryQuery}s for the method. * * @author Oliver Gierke + * @author Thomas Darimont */ public class QueryMethod { private final RepositoryMetadata metadata; private final Method method; + private final Class unwrappedReturnType; private final Parameters parameters; private Class domainClass; @@ -72,6 +76,7 @@ public class QueryMethod { this.method = method; this.parameters = createParameters(method); this.metadata = metadata; + this.unwrappedReturnType = potentiallyUnwrapReturnTypeFor(method); Assert.notNull(this.parameters); @@ -157,9 +162,9 @@ public class QueryMethod { */ public boolean isCollectionQuery() { - Class returnType = method.getReturnType(); return !(isPageQuery() || isSliceQuery()) - && org.springframework.util.ClassUtils.isAssignable(Iterable.class, returnType) || returnType.isArray(); + && org.springframework.util.ClassUtils.isAssignable(Iterable.class, unwrappedReturnType) + || unwrappedReturnType.isArray(); } /** @@ -169,9 +174,7 @@ public class QueryMethod { * @since 1.8 */ public boolean isSliceQuery() { - - Class returnType = method.getReturnType(); - return !isPageQuery() && org.springframework.util.ClassUtils.isAssignable(Slice.class, returnType); + return !isPageQuery() && org.springframework.util.ClassUtils.isAssignable(Slice.class, unwrappedReturnType); } /** @@ -180,9 +183,7 @@ public class QueryMethod { * @return */ public final boolean isPageQuery() { - - Class returnType = method.getReturnType(); - return org.springframework.util.ClassUtils.isAssignable(Page.class, returnType); + return org.springframework.util.ClassUtils.isAssignable(Page.class, unwrappedReturnType); } /** @@ -220,4 +221,14 @@ public class QueryMethod { public String toString() { return method.toString(); } + + private static Class potentiallyUnwrapReturnTypeFor(Method method) { + + if (QueryExecutionConverters.supports(method.getReturnType())) { + // unwrap only one level to handle cases like Future> correctly. + return ClassTypeInformation.fromReturnTypeOf(method).getComponentType().getType(); + } + + return method.getReturnType(); + } } diff --git a/src/test/java/org/springframework/data/repository/query/QueryMethodUnitTests.java b/src/test/java/org/springframework/data/repository/query/QueryMethodUnitTests.java index f3a4d6985..14ef596eb 100644 --- a/src/test/java/org/springframework/data/repository/query/QueryMethodUnitTests.java +++ b/src/test/java/org/springframework/data/repository/query/QueryMethodUnitTests.java @@ -20,6 +20,9 @@ import static org.junit.Assert.*; import java.io.Serializable; import java.lang.reflect.Method; +import java.util.List; +import java.util.concurrent.Future; +import java.util.stream.Stream; import org.junit.Test; import org.springframework.data.domain.Page; @@ -33,6 +36,7 @@ import org.springframework.data.repository.core.support.DefaultRepositoryMetadat * Unit tests for {@link QueryMethod}. * * @author Oliver Gierke + * @author Thomas Darimont */ public class QueryMethodUnitTests { @@ -138,6 +142,30 @@ public class QueryMethodUnitTests { assertThat(new QueryMethod(method, repositoryMetadata).isCollectionQuery(), is(true)); } + /** + * @see DATACMNS-716 + */ + @Test + public void doesNotRejectFutureQueryForSingleEntity() throws Exception { + + RepositoryMetadata repositoryMetadata = new DefaultRepositoryMetadata(SampleRepository.class); + Method method = SampleRepository.class.getMethod("returnsFutureForSingleEntity"); + + assertThat(new QueryMethod(method, repositoryMetadata).isCollectionQuery(), is(false)); + } + + /** + * @see DATACMNS-716 + */ + @Test + public void doesNotRejectFutureQueryForEntityCollection() throws Exception { + + RepositoryMetadata repositoryMetadata = new DefaultRepositoryMetadata(SampleRepository.class); + Method method = SampleRepository.class.getMethod("returnsFutureForEntityCollection"); + + assertThat(new QueryMethod(method, repositoryMetadata).isCollectionQuery(), is(true)); + } + interface SampleRepository extends Repository { String pagingMethodWithInvalidReturnType(Pageable pageable); @@ -157,6 +185,20 @@ public class QueryMethodUnitTests { Slice sliceOfUsers(); User[] arrayOfUsers(); + + Stream streaming(); + + Stream streaming(Pageable pageable); + + /** + * @see DATACMNS-716 + */ + Future returnsFutureForSingleEntity(); + + /** + * @see DATACMNS-716 + */ + Future> returnsFutureForEntityCollection(); } class User {