DATACMNS-1508 - Support for Kotlin Coroutines repositories.
We now support Kotlin Coroutines repositories backed by reactive repositories. Coroutine repositories can either invoke reactive query methods or implemented methods that are backed either by methods returning a reactive wrapper or that are native suspended functions.
Exclude Coroutines Continuation from bindable parameters and name discovery and do not unwrap results for suspended functions returning a reactive type.
interface CoroutinesRepository : CoroutineCrudRepository<User, String> {
suspend fun findOne(id: String): User
fun findByFirstname(firstname: String): Flow<User>
}
Original pull request: #415.
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2019 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 static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class DummyReactiveRepositoryFactory extends ReactiveRepositoryFactorySupport {
|
||||
|
||||
public final DummyRepositoryFactory.MyRepositoryQuery queryOne = mock(DummyRepositoryFactory.MyRepositoryQuery.class);
|
||||
public final RepositoryQuery queryTwo = mock(RepositoryQuery.class);
|
||||
public final QueryLookupStrategy strategy = mock(QueryLookupStrategy.class);
|
||||
|
||||
@SuppressWarnings("unchecked") private final QuerydslPredicateExecutor<Object> querydsl = mock(
|
||||
QuerydslPredicateExecutor.class);
|
||||
private final Object repository;
|
||||
|
||||
public DummyReactiveRepositoryFactory(Object repository) {
|
||||
|
||||
this.repository = repository;
|
||||
|
||||
when(strategy.resolveQuery(Mockito.any(Method.class), Mockito.any(RepositoryMetadata.class),
|
||||
Mockito.any(ProjectionFactory.class), Mockito.any(NamedQueries.class))).thenReturn(queryOne);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
|
||||
return mock(EntityInformation.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata)
|
||||
*/
|
||||
@Override
|
||||
protected Object getTargetRepository(RepositoryInformation information) {
|
||||
return repository;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryBaseClass(org.springframework.data.repository.core.RepositoryMetadata)
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||
return repository.getClass();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key, org.springframework.data.repository.query.EvaluationContextProvider)
|
||||
*/
|
||||
@Override
|
||||
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(Key key,
|
||||
QueryMethodEvaluationContextProvider evaluationContextProvider) {
|
||||
return Optional.of(strategy);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryFragments(org.springframework.data.repository.core.RepositoryMetadata)
|
||||
*/
|
||||
@Override
|
||||
protected RepositoryComposition.RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
|
||||
|
||||
RepositoryComposition.RepositoryFragments fragments = super.getRepositoryFragments(metadata);
|
||||
|
||||
return QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface()) //
|
||||
? fragments.append(RepositoryComposition.RepositoryFragments.just(querydsl)) //
|
||||
: fragments;
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupportUnitTests.MyRepositoryQuery;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
@@ -109,4 +108,11 @@ public class DummyRepositoryFactory extends RepositoryFactorySupport {
|
||||
? fragments.append(RepositoryFragments.just(querydsl)) //
|
||||
: fragments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static interface MyRepositoryQuery extends RepositoryQuery {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import static java.util.Collections.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.repository.core.support.DummyRepositoryFactory.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -93,8 +94,7 @@ public class RepositoryFactorySupportUnitTests {
|
||||
Mockito.reset(factory.strategy);
|
||||
|
||||
when(factory.strategy.resolveQuery(any(Method.class), any(RepositoryMetadata.class), any(ProjectionFactory.class),
|
||||
any(NamedQueries.class))).thenReturn(factory.queryOne,
|
||||
factory.queryTwo);
|
||||
any(NamedQueries.class))).thenReturn(factory.queryOne, factory.queryTwo);
|
||||
|
||||
factory.addQueryCreationListener(listener);
|
||||
factory.addQueryCreationListener(otherListener);
|
||||
@@ -309,7 +309,7 @@ public class RepositoryFactorySupportUnitTests {
|
||||
assertThatThrownBy( //
|
||||
() -> repository.findById("")) //
|
||||
.isInstanceOf(EmptyResultDataAccessException.class) //
|
||||
.hasMessageContaining("Result must not be null!");
|
||||
.hasMessageContaining("Result must not be null!");
|
||||
|
||||
assertThat(repository.findByUsername("")).isNull();
|
||||
}
|
||||
@@ -322,7 +322,7 @@ public class RepositoryFactorySupportUnitTests {
|
||||
assertThatThrownBy( //
|
||||
() -> repository.findByClass(null)) //
|
||||
.isInstanceOf(IllegalArgumentException.class) //
|
||||
.hasMessageContaining("must not be null!");
|
||||
.hasMessageContaining("must not be null!");
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1154
|
||||
@@ -427,10 +427,6 @@ public class RepositoryFactorySupportUnitTests {
|
||||
|
||||
}
|
||||
|
||||
interface MyRepositoryQuery extends RepositoryQuery {
|
||||
|
||||
}
|
||||
|
||||
interface ReadOnlyRepository<T, ID extends Serializable> extends Repository<T, ID> {
|
||||
|
||||
Optional<T> findById(ID id);
|
||||
|
||||
Reference in New Issue
Block a user