From a988df5d945b7d8090a35bbd961276d4f21f98aa Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 9 Jun 2020 11:21:10 +0200 Subject: [PATCH] DATACASS-771 - Fix return type detection for suspended Kotlin methods. See DATACMNS-1738 for further reference. --- .../query/ReactiveCassandraQueryMethod.java | 8 ++- ...eCassandraQueryMethodCoroutineUnitTests.kt | 62 +++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 spring-data-cassandra/src/test/kotlin/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryMethodCoroutineUnitTests.kt diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryMethod.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryMethod.java index ef23889c6..cda610064 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryMethod.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryMethod.java @@ -25,6 +25,7 @@ import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.util.ReactiveWrapperConverters; import org.springframework.data.repository.util.ReactiveWrappers; +import org.springframework.data.util.Lazy; /** * Reactive specific implementation of {@link CassandraQueryMethod}. @@ -34,7 +35,7 @@ import org.springframework.data.repository.util.ReactiveWrappers; */ public class ReactiveCassandraQueryMethod extends CassandraQueryMethod { - private final Method method; + private final Lazy isCollectionQuery; /** * Create a new {@link ReactiveCassandraQueryMethod} from the given {@link Method}. @@ -49,7 +50,8 @@ public class ReactiveCassandraQueryMethod extends CassandraQueryMethod { super(method, metadata, projectionFactory, mappingContext); - this.method = method; + this.isCollectionQuery = Lazy.of(() -> !(isPageQuery() || isSliceQuery()) + && ReactiveWrappers.isMultiValueType(metadata.getReturnType(method).getType())); } /* @@ -58,7 +60,7 @@ public class ReactiveCassandraQueryMethod extends CassandraQueryMethod { */ @Override public boolean isCollectionQuery() { - return !(isPageQuery() || isSliceQuery()) && ReactiveWrappers.isMultiValueType(method.getReturnType()); + return isCollectionQuery.get(); } /* diff --git a/spring-data-cassandra/src/test/kotlin/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryMethodCoroutineUnitTests.kt b/spring-data-cassandra/src/test/kotlin/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryMethodCoroutineUnitTests.kt new file mode 100644 index 000000000..36882821e --- /dev/null +++ b/spring-data-cassandra/src/test/kotlin/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryMethodCoroutineUnitTests.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.cassandra.repository.query + +import kotlinx.coroutines.flow.Flow +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.data.cassandra.core.mapping.CassandraMappingContext +import org.springframework.data.projection.SpelAwareProxyProjectionFactory +import org.springframework.data.repository.core.support.DefaultRepositoryMetadata +import org.springframework.data.repository.kotlin.CoroutineCrudRepository +import kotlin.coroutines.Continuation + +/** + * Unit tests for [ReactiveCassandraQueryMethod] using Coroutine repositories. + * + * @author Mark Paluch + */ +class ReactiveCassandraQueryMethodCoroutineUnitTests { + + val projectionFactory = SpelAwareProxyProjectionFactory() + + data class Person(val id: String) + + interface PersonRepository : CoroutineCrudRepository { + + suspend fun findSuspendAllByName(): Flow + + fun findAllByName(): Flow + } + + @Test // DATACASS-771 + internal fun `should consider methods returning Flow as collection queries`() { + + val method = PersonRepository::class.java.getMethod("findAllByName") + val queryMethod = ReactiveCassandraQueryMethod(method, DefaultRepositoryMetadata(PersonRepository::class.java), projectionFactory, CassandraMappingContext()) + + assertThat(queryMethod.isCollectionQuery).isTrue() + } + + @Test // DATACASS-771 + internal fun `should consider suspended methods returning Flow as collection queries`() { + + val method = PersonRepository::class.java.getMethod("findSuspendAllByName", Continuation::class.java) + val queryMethod = ReactiveCassandraQueryMethod(method, DefaultRepositoryMetadata(PersonRepository::class.java), projectionFactory, CassandraMappingContext()) + + assertThat(queryMethod.isCollectionQuery).isTrue() + } +}