diff --git a/src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryMethod.java b/src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryMethod.java index d86da64..931e8c4 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryMethod.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryMethod.java @@ -41,6 +41,7 @@ import org.springframework.data.repository.query.QueryMethod; import org.springframework.data.repository.util.ReactiveWrapperConverters; import org.springframework.data.repository.util.ReactiveWrappers; import org.springframework.data.util.ClassTypeInformation; +import org.springframework.data.util.Lazy; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -59,10 +60,10 @@ public class R2dbcQueryMethod extends QueryMethod { @SuppressWarnings("rawtypes") // private static final ClassTypeInformation SLICE_TYPE = ClassTypeInformation.from(Slice.class); - private final Method method; private final MappingContext, ? extends RelationalPersistentProperty> mappingContext; private final Optional query; private final boolean modifying; + private final Lazy isCollectionQuery; private @Nullable RelationalEntityMetadata metadata; @@ -110,10 +111,11 @@ public class R2dbcQueryMethod extends QueryMethod { } } - this.method = method; this.query = Optional.ofNullable( AnnotatedElementUtils.findMergedAnnotation(method, Query.class)); this.modifying = AnnotatedElementUtils.hasAnnotation(method, Modifying.class); + this.isCollectionQuery = Lazy.of(() -> !(isPageQuery() || isSliceQuery()) + && ReactiveWrappers.isMultiValueType(metadata.getReturnType(method).getType())); } /* (non-Javadoc) @@ -129,7 +131,7 @@ public class R2dbcQueryMethod extends QueryMethod { */ @Override public boolean isCollectionQuery() { - return !(isPageQuery() || isSliceQuery()) && ReactiveWrappers.isMultiValueType(method.getReturnType()); + return isCollectionQuery.get(); } /* (non-Javadoc) diff --git a/src/test/kotlin/org/springframework/data/r2dbc/repository/query/ReactiveR2dbcQueryMethodCoroutineUnitTests.kt b/src/test/kotlin/org/springframework/data/r2dbc/repository/query/ReactiveR2dbcQueryMethodCoroutineUnitTests.kt new file mode 100644 index 0000000..92cad37 --- /dev/null +++ b/src/test/kotlin/org/springframework/data/r2dbc/repository/query/ReactiveR2dbcQueryMethodCoroutineUnitTests.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.r2dbc.repository.query + +import kotlinx.coroutines.flow.Flow +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.data.projection.SpelAwareProxyProjectionFactory +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext +import org.springframework.data.repository.core.support.DefaultRepositoryMetadata +import org.springframework.data.repository.kotlin.CoroutineCrudRepository +import kotlin.coroutines.Continuation + +/** + * Unit tests for [R2dbcQueryMethod] using Coroutine repositories. + * + * @author Mark Paluch + */ +class ReactiveR2dbcQueryMethodCoroutineUnitTests { + + val projectionFactory = SpelAwareProxyProjectionFactory() + + data class Person(val id: String) + + interface PersonRepository : CoroutineCrudRepository { + + suspend fun findSuspendAllById(): Flow + + fun findAllById(): Flow + } + + @Test // gh-384 + internal fun `should consider methods returning Flow as collection queries`() { + + val method = PersonRepository::class.java.getMethod("findAllById") + val queryMethod = R2dbcQueryMethod(method, DefaultRepositoryMetadata(PersonRepository::class.java), projectionFactory, R2dbcMappingContext()) + + assertThat(queryMethod.isCollectionQuery).isTrue() + } + + @Test // gh-384 + internal fun `should consider suspended methods returning Flow as collection queries`() { + + val method = PersonRepository::class.java.getMethod("findSuspendAllById", Continuation::class.java) + val queryMethod = R2dbcQueryMethod(method, DefaultRepositoryMetadata(PersonRepository::class.java), projectionFactory, R2dbcMappingContext()) + + assertThat(queryMethod.isCollectionQuery).isTrue() + } +}