Browse Source

Decouple Paging and Sorting repositories from CrudRepository.

This way they can be combined with different variants of CrudRepositories.

This affects
`PagingAndSortingRepository`, `ReactiveSortingRepository`, `CoroutineSortingRepository`, and `RxJavaSortingRepository`.

Any repository implementing those interfaces now needs to also implement a suitable CRUD repository, or needs to manually add the methods from a CRUD repository as needed.

Closes #2537
Original pull request: #2540.
pull/2571/head
Jens Schauder 4 years ago committed by Mark Paluch
parent
commit
37eee0e35d
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 34
      src/main/asciidoc/repositories.adoc
  2. 9
      src/main/java/org/springframework/data/repository/PagingAndSortingRepository.java
  3. 10
      src/main/java/org/springframework/data/repository/reactive/ReactiveSortingRepository.java
  4. 11
      src/main/java/org/springframework/data/repository/reactive/RxJava3SortingRepository.java
  5. 3
      src/main/java/org/springframework/data/repository/support/DefaultRepositoryInvokerFactory.java
  6. 4
      src/main/java/org/springframework/data/repository/support/PagingAndSortingRepositoryInvoker.java
  7. 9
      src/main/kotlin/org/springframework/data/repository/kotlin/CoroutineSortingRepository.kt
  8. 7
      src/test/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadataUnitTests.java
  9. 2
      src/test/java/org/springframework/data/repository/core/support/DefaultCrudMethodsUnitTests.java
  10. 22
      src/test/java/org/springframework/data/repository/core/support/DefaultRepositoryInformationUnitTests.java
  11. 2
      src/test/java/org/springframework/data/repository/core/support/ReactiveRepositoryInformationUnitTests.java
  12. 3
      src/test/java/org/springframework/data/repository/core/support/ReactiveWrapperRepositoryFactorySupportUnitTests.java
  13. 10
      src/test/java/org/springframework/data/repository/core/support/RepositoryFactorySupportUnitTests.java
  14. 2
      src/test/java/org/springframework/data/repository/support/CrudRepositoryInvokerUnitTests.java
  15. 3
      src/test/java/org/springframework/data/repository/support/DefaultRepositoryInvokerFactoryIntegrationTests.java
  16. 107
      src/test/java/org/springframework/data/repository/support/PaginginAndSortingRepositoryInvokerUnitTests.java

34
src/main/asciidoc/repositories.adoc

@ -58,13 +58,13 @@ public interface CrudRepository<T, ID> extends Repository<T, ID> { @@ -58,13 +58,13 @@ public interface CrudRepository<T, ID> extends Repository<T, ID> {
NOTE: We also provide persistence technology-specific abstractions, such as `JpaRepository` or `MongoRepository`.
Those interfaces extend `CrudRepository` and expose the capabilities of the underlying persistence technology in addition to the rather generic persistence technology-agnostic interfaces such as `CrudRepository`.
On top of the `CrudRepository`, there is a https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/PagingAndSortingRepository.html[`PagingAndSortingRepository`] abstraction that adds additional methods to ease paginated access to entities:
Additional to the `CrudRepository`, there is a https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/PagingAndSortingRepository.html[`PagingAndSortingRepository`] abstraction that adds additional methods to ease paginated access to entities:
.`PagingAndSortingRepository` interface
====
[source,java]
----
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
public interface PagingAndSortingRepository<T, ID> {
Iterable<T> findAll(Sort sort);
@ -210,17 +210,35 @@ The sections that follow explain each step in detail: @@ -210,17 +210,35 @@ The sections that follow explain each step in detail:
To define a repository interface, you first need to define a domain class-specific repository interface.
The interface must extend `Repository` and be typed to the domain class and an ID type.
If you want to expose CRUD methods for that domain type, extend `CrudRepository` instead of `Repository`.
If you want to expose CRUD methods for that domain type, you may extend `CrudRepository`, or one of its variants instead of `Repository`.
[[repositories.definition-tuning]]
=== Fine-tuning Repository Definition
Typically, your repository interface extends `Repository`, `CrudRepository`, or `PagingAndSortingRepository`.
Alternatively, if you do not want to extend Spring Data interfaces, you can also annotate your repository interface with `@RepositoryDefinition`.
Extending `CrudRepository` exposes a complete set of methods to manipulate your entities.
If you prefer to be selective about the methods being exposed, copy the methods you want to expose from `CrudRepository` into your domain repository.
There are a few variants how you can get started with your repository interface.
NOTE: Doing so lets you define your own abstractions on top of the provided Spring Data Repositories functionality.
The typical approach is to extend `CrudRepository`, which gives you methods for CRUD functionality.
CRUD stands for Create, Read, Update, Delete.
With version 3.0 we also introduced `ListCrudRepository` which is very similar to the `CrudRepository` but for those methods that return multiple entities it returns a `List` instead of an `Iterable` which you might find easier to use.
If you are using a reactive store you might choose `ReactiveCrudRepository`, or `RxJava3CrudRepository` depending on which reactive framework you are using.
If you are using Kotlin you might pick `CoroutineCrudRepository` which utilizes Kotlin's coroutines.
Additional you can extend `PagingAndSortingRepository`, `ReactiveSortingRepository`, `RxJava3SortingRepository`, or `CoroutineSortingRepository` if you need methods that allow to specify a `Sort` abstraction or in the first case a `Pageable` abstraction.
Note that the various sorting repositories no longer extended their respective CRUD repository as they did in Spring Data Versions pre 3.0.
Therefore, you need to extend both interfaces if you want functionality of both.
If you do not want to extend Spring Data interfaces, you can also annotate your repository interface with `@RepositoryDefinition`.
Extending one of the CRUD repository interfaces exposes a complete set of methods to manipulate your entities.
If you prefer to be selective about the methods being exposed, copy the methods you want to expose from the CRUD repository into your domain repository.
When doing so, you may change the return type of methods.
Spring Data will honor the return type if possible.
For example, for methods returning multiple entities you may choose `Iterable<T>`, `List<T>`, `Collection<T>` or a VAVR list.
If many repositories in your application should have the same set of methods you can define your own base interface to inherit from.
Such an interface must be annotated with `@NoRepositoryBean`.
This prevents Spring Data to try to create an instance of it directly and failing because it can't determine the entity for that repository, since it still contains a generic type variable.
The following example shows how to selectively expose CRUD methods (`findById` and `save`, in this case):

9
src/main/java/org/springframework/data/repository/PagingAndSortingRepository.java

@ -20,16 +20,19 @@ import org.springframework.data.domain.Pageable; @@ -20,16 +20,19 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
/**
* Extension of {@link CrudRepository} to provide additional methods to retrieve entities using the pagination and
* sorting abstraction.
* Repository fragment to provide methods to retrieve entities using the pagination and sorting abstraction. In many
* cases this will be combined with {@link CrudRepository} or similar or with manually added methods to provide CRUD
* functionality.
*
* @author Oliver Gierke
* @author Jens Schauder
* @see Sort
* @see Pageable
* @see Page
* @see CrudRepository
*/
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
public interface PagingAndSortingRepository<T, ID> extends Repository<T, ID> {
/**
* Returns all entities sorted by the given options.

10
src/main/java/org/springframework/data/repository/reactive/ReactiveSortingRepository.java

@ -20,20 +20,24 @@ import reactor.core.publisher.Mono; @@ -20,20 +20,24 @@ import reactor.core.publisher.Mono;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository;
/**
* Extension of {@link ReactiveCrudRepository} to provide additional methods to retrieve entities using the sorting
* abstraction.
* Repository fragment to provide methods to retrieve entities using the sorting abstraction. In many cases it
* should be combined with {@link ReactiveCrudRepository} or a similar repository interface in order to add CRUD
* functionality.
*
* @author Mark Paluch
* @author Christoph Strobl
* @author Jens Schauder
* @since 2.0
* @see Sort
* @see Mono
* @see Flux
* @see ReactiveCrudRepository
*/
@NoRepositoryBean
public interface ReactiveSortingRepository<T, ID> extends ReactiveCrudRepository<T, ID> {
public interface ReactiveSortingRepository<T, ID> extends Repository<T, ID> {
/**
* Returns all entities sorted by the given options.

11
src/main/java/org/springframework/data/repository/reactive/RxJava3SortingRepository.java

@ -19,18 +19,21 @@ import io.reactivex.rxjava3.core.Flowable; @@ -19,18 +19,21 @@ import io.reactivex.rxjava3.core.Flowable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository;
/**
* Extension of {@link RxJava3CrudRepository} to provide additional methods to retrieve entities using the sorting
* abstraction.
*
* Repository fragment to provide methods to retrieve entities using the sorting abstraction. In many cases this
* should be combined with {@link RxJava3CrudRepository} or a similar interface to provide CRUD functionality.
*
* @author Mark Paluch
* @author Jens Schauder
* @since 2.4
* @see Sort
* @see Flowable
* @see RxJava3CrudRepository
*/
@NoRepositoryBean
public interface RxJava3SortingRepository<T, ID> extends RxJava3CrudRepository<T, ID> {
public interface RxJava3SortingRepository<T, ID> extends Repository<T, ID> {
/**
* Returns all entities sorted by the given options.

3
src/main/java/org/springframework/data/repository/support/DefaultRepositoryInvokerFactory.java

@ -35,6 +35,7 @@ import org.springframework.util.Assert; @@ -35,6 +35,7 @@ import org.springframework.util.Assert;
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Jens Schauder
* @since 1.10
*/
public class DefaultRepositoryInvokerFactory implements RepositoryInvokerFactory {
@ -93,7 +94,7 @@ public class DefaultRepositoryInvokerFactory implements RepositoryInvokerFactory @@ -93,7 +94,7 @@ public class DefaultRepositoryInvokerFactory implements RepositoryInvokerFactory
@SuppressWarnings("unchecked")
protected RepositoryInvoker createInvoker(RepositoryInformation information, Object repository) {
if (repository instanceof PagingAndSortingRepository) {
if (repository instanceof PagingAndSortingRepository && repository instanceof CrudRepository) {
return new PagingAndSortingRepositoryInvoker((PagingAndSortingRepository<Object, Object>) repository, information,
conversionService);
} else if (repository instanceof CrudRepository) {

4
src/main/java/org/springframework/data/repository/support/PagingAndSortingRepositoryInvoker.java

@ -21,6 +21,7 @@ import java.util.Optional; @@ -21,6 +21,7 @@ import java.util.Optional;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.core.RepositoryMetadata;
@ -29,6 +30,7 @@ import org.springframework.data.repository.core.RepositoryMetadata; @@ -29,6 +30,7 @@ import org.springframework.data.repository.core.RepositoryMetadata;
* avoid reflection overhead introduced by the superclass.
*
* @author Oliver Gierke
* @author Jens Schauder
* @since 1.10
*/
class PagingAndSortingRepositoryInvoker extends CrudRepositoryInvoker {
@ -47,7 +49,7 @@ class PagingAndSortingRepositoryInvoker extends CrudRepositoryInvoker { @@ -47,7 +49,7 @@ class PagingAndSortingRepositoryInvoker extends CrudRepositoryInvoker {
public PagingAndSortingRepositoryInvoker(PagingAndSortingRepository<Object, Object> repository,
RepositoryMetadata metadata, ConversionService conversionService) {
super(repository, metadata, conversionService);
super((CrudRepository<Object, Object>) repository, metadata, conversionService);
var crudMethods = metadata.getCrudMethods();

9
src/main/kotlin/org/springframework/data/repository/kotlin/CoroutineSortingRepository.kt

@ -18,18 +18,23 @@ package org.springframework.data.repository.kotlin @@ -18,18 +18,23 @@ package org.springframework.data.repository.kotlin
import kotlinx.coroutines.flow.Flow
import org.springframework.data.domain.Sort
import org.springframework.data.repository.NoRepositoryBean
import org.springframework.data.repository.Repository
/**
* Extension of [CoroutineCrudRepository] to provide additional methods to retrieve entities using the sorting
* Repository fragment to provide methods to retrieve entities using the sorting
* abstraction.
*
* In many cases this should be combined with [CoroutineCrudRepository] or similar or manually added methods to provide CRUD functionality.
*
* @author Mark Paluch
* @author Jens Schauder
* @since 2.3
* @see Flow
* @see Sort
* @see CoroutineCrudRepository
*/
@NoRepositoryBean
interface CoroutineSortingRepository<T, ID> : CoroutineCrudRepository<T, ID> {
interface CoroutineSortingRepository<T, ID> : Repository<T, ID> {
/**
* Returns all entities sorted by the given options.

7
src/test/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadataUnitTests.java

@ -27,6 +27,7 @@ import org.springframework.core.ResolvableType; @@ -27,6 +27,7 @@ import org.springframework.core.ResolvableType;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryMetadata;
@ -95,7 +96,7 @@ class AbstractRepositoryMetadataUnitTests { @@ -95,7 +96,7 @@ class AbstractRepositoryMetadataUnitTests {
@Test // DATACMNS-471
void detectsArrayReturnTypeCorrectly() throws Exception {
RepositoryMetadata metadata = new DefaultRepositoryMetadata(PagedRepository.class);
RepositoryMetadata metadata = new DefaultRepositoryMetadata(CompletePageableAndSortingRepository.class);
var method = PagedRepository.class.getMethod("returnsArray");
assertThat(metadata.getReturnedDomainClass(method)).isEqualTo(User.class);
@ -169,4 +170,8 @@ class AbstractRepositoryMetadataUnitTests { @@ -169,4 +170,8 @@ class AbstractRepositoryMetadataUnitTests {
interface ContainerRepository extends Repository<Container, Long> {
Container someMethod();
}
interface CompletePageableAndSortingRepository extends PagingAndSortingRepository<Container, Long> {
}
}

2
src/test/java/org/springframework/data/repository/core/support/DefaultCrudMethodsUnitTests.java

@ -197,7 +197,7 @@ class DefaultCrudMethodsUnitTests { @@ -197,7 +197,7 @@ class DefaultCrudMethodsUnitTests {
interface DomainCrudRepository extends CrudRepository<Domain, Long> {}
interface DomainPagingAndSortingRepository extends PagingAndSortingRepository<Domain, Long> {}
interface DomainPagingAndSortingRepository extends PagingAndSortingRepository<Domain, Long>, CrudRepository<Domain, Long> {}
interface RepositoryWithCustomSave extends Repository<Domain, Serializable> {

22
src/test/java/org/springframework/data/repository/core/support/DefaultRepositoryInformationUnitTests.java

@ -111,27 +111,11 @@ class DefaultRepositoryInformationUnitTests { @@ -111,27 +111,11 @@ class DefaultRepositoryInformationUnitTests {
assertThat(information.hasCustomMethod()).isFalse();
}
@Test
void discoversIntermediateMethodsAsBackingMethods() throws NoSuchMethodException, SecurityException {
var metadata = new DefaultRepositoryMetadata(CustomRepository.class);
var information = new DefaultRepositoryInformation(metadata,
PagingAndSortingRepository.class, RepositoryComposition.empty());
var method = CustomRepository.class.getMethod("findAll", Pageable.class);
assertThat(information.isBaseClassMethod(method)).isTrue();
method = getMethodFrom(CustomRepository.class, "existsById");
assertThat(information.isBaseClassMethod(method)).isTrue();
assertThat(information.getQueryMethods()).isEmpty();
}
@Test // DATACMNS-151
void doesNotConsiderManuallyDefinedSaveMethodAQueryMethod() {
RepositoryMetadata metadata = new DefaultRepositoryMetadata(CustomRepository.class);
RepositoryInformation information = new DefaultRepositoryInformation(metadata, PagingAndSortingRepository.class,
RepositoryInformation information = new DefaultRepositoryInformation(metadata, CompletePageableAndSortingRepository.class,
RepositoryComposition.empty());
assertThat(information.getQueryMethods()).isEmpty();
@ -427,4 +411,8 @@ class DefaultRepositoryInformationUnitTests { @@ -427,4 +411,8 @@ class DefaultRepositoryInformationUnitTests {
return entity;
}
}
interface CompletePageableAndSortingRepository<T, ID> extends CrudRepository<T, ID>, PagingAndSortingRepository<T, ID> {
}
}

2
src/test/java/org/springframework/data/repository/core/support/ReactiveRepositoryInformationUnitTests.java

@ -66,7 +66,7 @@ class ReactiveRepositoryInformationUnitTests { @@ -66,7 +66,7 @@ class ReactiveRepositoryInformationUnitTests {
@Test // DATACMNS-836
void discoversMethodAssignableArguments() throws Exception {
var reference = extractTargetMethodFromRepository(ReactiveSortingRepository.class, "saveAll", Publisher.class);
var reference = extractTargetMethodFromRepository(ReactiveCrudRepository.class, "saveAll", Publisher.class);
assertThat(reference.getDeclaringClass()).isEqualTo(ReactiveCrudRepository.class);
assertThat(reference.getName()).isEqualTo("saveAll");

3
src/test/java/org/springframework/data/repository/core/support/ReactiveWrapperRepositoryFactorySupportUnitTests.java

@ -20,6 +20,7 @@ import static org.mockito.Mockito.*; @@ -20,6 +20,7 @@ import static org.mockito.Mockito.*;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.core.Single;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Mono;
import java.io.Serializable;
@ -47,7 +48,7 @@ class ReactiveWrapperRepositoryFactorySupportUnitTests { @@ -47,7 +48,7 @@ class ReactiveWrapperRepositoryFactorySupportUnitTests {
DummyRepositoryFactory factory;
@Mock ReactiveSortingRepository<Object, Serializable> backingRepo;
@Mock ReactiveCrudRepository<Object, Serializable> backingRepo;
@Mock ObjectRepositoryCustom customImplementation;
@BeforeEach

10
src/test/java/org/springframework/data/repository/core/support/RepositoryFactorySupportUnitTests.java

@ -51,6 +51,7 @@ import org.springframework.data.domain.Pageable; @@ -51,6 +51,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.RepositoryDefinition;
@ -90,7 +91,7 @@ class RepositoryFactorySupportUnitTests { @@ -90,7 +91,7 @@ class RepositoryFactorySupportUnitTests {
DummyRepositoryFactory factory;
@Mock PagingAndSortingRepository<Object, Object> backingRepo;
@Mock CrudRepository<Object, Object> backingRepo;
@Mock ObjectRepositoryCustom customImplementation;
@Mock MyQueryCreationListener listener;
@ -167,12 +168,11 @@ class RepositoryFactorySupportUnitTests { @@ -167,12 +168,11 @@ class RepositoryFactorySupportUnitTests {
void createsRepositoryInstanceWithCustomIntermediateRepository() {
var repository = factory.getRepository(CustomRepository.class);
Pageable pageable = PageRequest.of(0, 10);
when(backingRepo.findAll(pageable)).thenReturn(new PageImpl<>(Collections.emptyList()));
repository.findAll(pageable);
when(backingRepo.findAll()).thenReturn(new PageImpl<>(Collections.emptyList()));
repository.findAll();
verify(backingRepo, times(1)).findAll(pageable);
verify(backingRepo, times(1)).findAll();
}
@Test

2
src/test/java/org/springframework/data/repository/support/CrudRepositoryInvokerUnitTests.java

@ -153,7 +153,7 @@ class CrudRepositoryInvokerUnitTests { @@ -153,7 +153,7 @@ class CrudRepositoryInvokerUnitTests {
static class Person {}
interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
interface PersonRepository extends PagingAndSortingRepository<Person, Long>, CrudRepository<Person, Long> {
Page<Person> findByFirstName(@Param("firstName") String firstName, Pageable pageable);

3
src/test/java/org/springframework/data/repository/support/DefaultRepositoryInvokerFactoryIntegrationTests.java

@ -93,7 +93,6 @@ class DefaultRepositoryInvokerFactoryIntegrationTests { @@ -93,7 +93,6 @@ class DefaultRepositoryInvokerFactoryIntegrationTests {
var invoker = factory.getInvokerFor(User.class);
assertThat(invoker)//
.isInstanceOf(CrudRepositoryInvoker.class)//
.isNotInstanceOf(PagingAndSortingRepositoryInvoker.class);
.isInstanceOf(CrudRepositoryInvoker.class);
}
}

107
src/test/java/org/springframework/data/repository/support/PaginginAndSortingRepositoryInvokerUnitTests.java

@ -1,107 +0,0 @@ @@ -1,107 +0,0 @@
/*
* Copyright 2014-2021 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.support;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.repository.support.RepositoryInvocationTestUtils.*;
import org.junit.jupiter.api.Test;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.format.support.DefaultFormattingConversionService;
/**
* Unit tests for {@link PagingAndSortingRepositoryInvoker}.
*
* @author Oliver Gierke
*/
class PaginginAndSortingRepositoryInvokerUnitTests {
@Test // DATACMNS-589
void invokesFindAllWithPageableByDefault() throws Exception {
var repository = mock(Repository.class);
var method = PagingAndSortingRepository.class.getMethod("findAll", Pageable.class);
getInvokerFor(repository, expectInvocationOf(method)).invokeFindAll(PageRequest.of(0, 10));
getInvokerFor(repository, expectInvocationOf(method)).invokeFindAll(Pageable.unpaged());
}
@Test // DATACMNS-589
void invokesFindAllWithSortByDefault() throws Exception {
var repository = mock(Repository.class);
var method = PagingAndSortingRepository.class.getMethod("findAll", Sort.class);
getInvokerFor(repository, expectInvocationOf(method)).invokeFindAll(Sort.by("foo"));
getInvokerFor(repository, expectInvocationOf(method)).invokeFindAll(Sort.unsorted());
}
@Test // DATACMNS-589
void invokesRedeclaredFindAllWithPageable() throws Exception {
var repository = mock(RepositoryWithRedeclaredFindAllWithPageable.class);
var method = RepositoryWithRedeclaredFindAllWithPageable.class.getMethod("findAll", Pageable.class);
when(repository.findAll(any(Pageable.class))).thenReturn(Page.empty());
getInvokerFor(repository, expectInvocationOf(method)).invokeFindAll(PageRequest.of(0, 10));
getInvokerFor(repository, expectInvocationOf(method)).invokeFindAll(Pageable.unpaged());
}
@Test // DATACMNS-589
void invokesRedeclaredFindAllWithSort() throws Exception {
var repository = mock(RepositoryWithRedeclaredFindAllWithSort.class);
var method = RepositoryWithRedeclaredFindAllWithSort.class.getMethod("findAll", Sort.class);
getInvokerFor(repository, expectInvocationOf(method)).invokeFindAll(Sort.by("foo"));
getInvokerFor(repository, expectInvocationOf(method)).invokeFindAll(Sort.unsorted());
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static RepositoryInvoker getInvokerFor(Object repository) {
RepositoryMetadata metadata = new DefaultRepositoryMetadata(repository.getClass().getInterfaces()[0]);
GenericConversionService conversionService = new DefaultFormattingConversionService();
return new PagingAndSortingRepositoryInvoker((PagingAndSortingRepository) repository, metadata, conversionService);
}
private static RepositoryInvoker getInvokerFor(Object repository, VerifyingMethodInterceptor interceptor) {
return getInvokerFor(getVerifyingRepositoryProxy(repository, interceptor));
}
interface Repository extends PagingAndSortingRepository<Object, Long> {}
interface RepositoryWithRedeclaredFindAllWithPageable extends PagingAndSortingRepository<Object, Long> {
Page<Object> findAll(Pageable pageable);
}
interface RepositoryWithRedeclaredFindAllWithSort extends PagingAndSortingRepository<Object, Long> {
Page<Object> findAll(Sort sort);
}
}
Loading…
Cancel
Save