diff --git a/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java b/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java index a2dd8ed76..e166c8943 100644 --- a/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java +++ b/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java @@ -20,11 +20,13 @@ import java.util.Collection; import java.util.Set; import org.springframework.data.repository.support.Repositories; +import org.springframework.data.util.TypeInformation; /** * Metadata for repository interfaces. * * @author Oliver Gierke + * @author Mark Paluch */ public interface RepositoryMetadata { @@ -50,11 +52,22 @@ public interface RepositoryMetadata { Class getRepositoryInterface(); /** - * Returns the domain class returned by the given {@link Method}. Will extract the type from {@link Collection}s and - * {@link org.springframework.data.domain.Page} as well. + * Returns the type {@link Method} return type as it is declared in the repository. Considers suspended methods and + * does not unwrap component types but leaves those for further inspection. * * @param method * @return + * @since 2.3.1 + */ + TypeInformation getReturnType(Method method); + + /** + * Returns the domain class returned by the given {@link Method}. In contrast to {@link #getReturnType(Method)}, this + * method extracts the type from {@link Collection}s and {@link org.springframework.data.domain.Page} as well. + * + * @param method + * @return + * @see #getReturnType(Method) */ Class getReturnedDomainClass(Method method); diff --git a/src/main/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadata.java b/src/main/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadata.java index 740e73291..44b6c6f57 100644 --- a/src/main/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadata.java +++ b/src/main/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadata.java @@ -40,6 +40,7 @@ import org.springframework.util.Assert; * @author Oliver Gierke * @author Thomas Darimont * @author Jens Schauder + * @author Mark Paluch */ public abstract class AbstractRepositoryMetadata implements RepositoryMetadata { @@ -79,9 +80,10 @@ public abstract class AbstractRepositoryMetadata implements RepositoryMetadata { /* * (non-Javadoc) - * @see org.springframework.data.repository.core.RepositoryMetadata#getReturnedDomainClass(java.lang.reflect.Method) + * @see org.springframework.data.repository.core.RepositoryMetadata#getReturnType(java.lang.reflect.Method) */ - public Class getReturnedDomainClass(Method method) { + @Override + public TypeInformation getReturnType(Method method) { TypeInformation returnType = null; if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinReflectionUtils.isSuspend(method)) { @@ -95,7 +97,15 @@ public abstract class AbstractRepositoryMetadata implements RepositoryMetadata { returnType = typeInformation.getReturnType(method); } - return QueryExecutionConverters.unwrapWrapperTypes(returnType).getType(); + return returnType; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.RepositoryMetadata#getReturnedDomainClass(java.lang.reflect.Method) + */ + public Class getReturnedDomainClass(Method method) { + return QueryExecutionConverters.unwrapWrapperTypes(getReturnType(method)).getType(); } /* diff --git a/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java b/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java index 0aa0d0e4c..fb73594bd 100644 --- a/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java +++ b/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java @@ -32,6 +32,7 @@ import org.springframework.data.repository.core.CrudMethods; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.util.Streamable; +import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -244,6 +245,15 @@ class DefaultRepositoryInformation implements RepositoryInformation { return metadata.getReturnedDomainClass(method); } + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.RepositoryMetadata#getReturnType(java.lang.reflect.Method) + */ + @Override + public TypeInformation getReturnType(Method method) { + return metadata.getReturnType(method); + } + /* * (non-Javadoc) * @see org.springframework.data.repository.core.RepositoryMetadata#getCrudMethods() diff --git a/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.java b/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.java index ac9e775fa..b8de47ade 100644 --- a/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.java +++ b/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.java @@ -22,6 +22,7 @@ import org.springframework.data.repository.core.CrudMethods; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.util.Streamable; +import org.springframework.data.util.TypeInformation; public final class DummyRepositoryInformation implements RepositoryInformation { @@ -47,6 +48,11 @@ public final class DummyRepositoryInformation implements RepositoryInformation { return metadata.getRepositoryInterface(); } + @Override + public TypeInformation getReturnType(Method method) { + return metadata.getReturnType(method); + } + public Class getReturnedDomainClass(Method method) { return getDomainType(); } diff --git a/src/test/kotlin/org/springframework/data/repository/core/support/CoroutineRepositoryMetadataUnitTests.kt b/src/test/kotlin/org/springframework/data/repository/core/support/CoroutineRepositoryMetadataUnitTests.kt new file mode 100644 index 000000000..86b763e40 --- /dev/null +++ b/src/test/kotlin/org/springframework/data/repository/core/support/CoroutineRepositoryMetadataUnitTests.kt @@ -0,0 +1,55 @@ +/* + * 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.repository.core.support + +import kotlinx.coroutines.flow.Flow +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.data.mapping.Person +import org.springframework.data.repository.Repository +import org.springframework.data.repository.core.RepositoryMetadata +import kotlin.coroutines.Continuation + +/** + * Coroutine unit tests for [RepositoryMetadata]. + * + * @author Mark Paluch + */ +class CoroutineRepositoryMetadataUnitTests { + + var metadata: RepositoryMetadata = DefaultRepositoryMetadata(MyCoroutineRepository::class.java) + + @Test // DATACMNS-1508 + fun `should consider Flow return type`() { + + val queryMethod = MyCoroutineRepository::class.java.getDeclaredMethod("suspendedQueryMethod", Continuation::class.java) + assertThat(metadata.getReturnType(queryMethod).type).isEqualTo(Flow::class.java) + } + + @Test // DATACMNS-1508 + fun `should consider suspended Flow return`() { + + val queryMethod = MyCoroutineRepository::class.java.getDeclaredMethod("queryMethod") + assertThat(metadata.getReturnType(queryMethod).type).isEqualTo(Flow::class.java) + } + + interface MyCoroutineRepository : Repository { + + suspend fun suspendedQueryMethod(): Flow + + fun queryMethod(): Flow + } +}