From b1f5717d63a13760393fa30a372fe9743935ec51 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 31 Jul 2020 11:11:41 +0200 Subject: [PATCH] DATAMONGO-2601 - Suppress results for suspended query methods returning kotlin.Unit. We now discard results for suspended query methods if the return type is kotlin.Unit. Related ticket: DATACMNS-1779 --- .../query/ReactiveMongoQueryExecution.java | 7 +- .../CoroutineRepositoryUnitTests.kt | 68 +++++++++++++++++++ .../repository/KotlinRepositoryUnitTests.kt | 61 +++++++++++++++++ 3 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/repository/CoroutineRepositoryUnitTests.kt create mode 100644 spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/repository/KotlinRepositoryUnitTests.kt diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryExecution.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryExecution.java index 2ca038ba8..66fe7c849 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryExecution.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryExecution.java @@ -32,6 +32,7 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.repository.query.ResultProcessor; import org.springframework.data.repository.query.ReturnedType; import org.springframework.data.repository.util.ReactiveWrappers; +import org.springframework.data.util.ReflectionUtils; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -203,7 +204,7 @@ interface ReactiveMongoQueryExecution { ReturnedType returnedType = processor.getReturnedType(); - if (isVoid(returnedType)) { + if (ReflectionUtils.isVoid(returnedType.getReturnedType())) { if (source instanceof Mono) { return ((Mono) source).then(); @@ -228,8 +229,4 @@ interface ReactiveMongoQueryExecution { return processor.processResult(source, converter); } } - - static boolean isVoid(ReturnedType returnedType) { - return returnedType.getReturnedType().equals(Void.class); - } } diff --git a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/repository/CoroutineRepositoryUnitTests.kt b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/repository/CoroutineRepositoryUnitTests.kt new file mode 100644 index 000000000..3d49709b8 --- /dev/null +++ b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/repository/CoroutineRepositoryUnitTests.kt @@ -0,0 +1,68 @@ +/* + * 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.mongodb.repository + +import com.mongodb.client.result.DeleteResult +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.ReactiveMongoOperations +import org.springframework.data.mongodb.core.convert.MappingMongoConverter +import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver +import org.springframework.data.mongodb.core.mapping.MongoMappingContext +import org.springframework.data.mongodb.repository.support.ReactiveMongoRepositoryFactory +import org.springframework.data.repository.kotlin.CoroutineCrudRepository +import reactor.core.publisher.Mono + +/** + * Unit tests for Kotlin Coroutine repositories. + * + * @author Mark Paluch + */ +class CoroutineRepositoryUnitTests { + + val operations = mockk(relaxed = true) + lateinit var repositoryFactory: ReactiveMongoRepositoryFactory + + @BeforeEach + fun before() { + + every { operations.getConverter() } returns MappingMongoConverter(NoOpDbRefResolver.INSTANCE, MongoMappingContext()) + repositoryFactory = ReactiveMongoRepositoryFactory(operations) + } + + @Test // DATAMONGO-2601 + fun `should discard result of suspended query method without result`() { + + every { operations.remove(any(), any(), any()) } returns Mono.just(DeleteResult.acknowledged(1)) + + val repository = repositoryFactory.getRepository(PersonRepository::class.java) + + runBlocking { + repository.deleteAllByName("foo") + } + } + + interface PersonRepository : CoroutineCrudRepository { + + suspend fun deleteAllByName(name: String) + } + + data class Person(@Id var id: Long, var name: String) +} diff --git a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/repository/KotlinRepositoryUnitTests.kt b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/repository/KotlinRepositoryUnitTests.kt new file mode 100644 index 000000000..de8fb9255 --- /dev/null +++ b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/repository/KotlinRepositoryUnitTests.kt @@ -0,0 +1,61 @@ +/* + * 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.mongodb.repository + +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.MongoOperations +import org.springframework.data.mongodb.core.convert.MappingMongoConverter +import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver +import org.springframework.data.mongodb.core.mapping.MongoMappingContext +import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory +import org.springframework.data.repository.CrudRepository + +/** + * Unit tests for Kotlin repositories. + * + * @author Mark Paluch + */ +class KotlinRepositoryUnitTests { + + val operations = mockk(relaxed = true) + lateinit var repositoryFactory: MongoRepositoryFactory + + @BeforeEach + fun before() { + + every { operations.getConverter() } returns MappingMongoConverter(NoOpDbRefResolver.INSTANCE, MongoMappingContext()) + repositoryFactory = MongoRepositoryFactory(operations) + } + + @Test // DATAMONGO-2601 + fun should() { + + val repository = repositoryFactory.getRepository(PersonRepository::class.java) + + repository.deleteAllByName("foo") + } + + interface PersonRepository : CrudRepository { + + fun deleteAllByName(name: String) + } + + data class Person(@Id var id: Long, var name: String) +}