Skip to content

Decouple Paging and Sorting repositories from CrudRepository #2540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>3.0.0-SNAPSHOT</version>
<version>3.0.0-2537-split-pagingandsortingrep-SNAPSHOT</version>

<name>Spring Data Core</name>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@
import org.springframework.data.domain.Sort;

/**
* Extension of {@link CrudRepository} to provide additional methods to retrieve entities using the pagination and
* sorting abstraction.
* Repository interface 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,24 @@

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 interface that provides 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@

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 interface that provides 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Jens Schauder
* @since 1.10
*/
public class DefaultRepositoryInvokerFactory implements RepositoryInvokerFactory {
Expand Down Expand Up @@ -93,7 +94,7 @@ private RepositoryInvoker prepareInvokers(Class<?> domainType) {
@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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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;

Expand All @@ -29,6 +30,7 @@
* avoid reflection overhead introduced by the superclass.
*
* @author Oliver Gierke
* @author Jens Schauder
* @since 1.10
*/
class PagingAndSortingRepositoryInvoker extends CrudRepositoryInvoker {
Expand All @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,30 @@ 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 interface that provides 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.
*
* @param sort must not be null.
* @return all entities sorted by the given options.
* @throws IllegalArgumentException in case the given [Sort] is null.
*/
fun findAll(sort: Sort): Flow<T>
/**
* Returns all entities sorted by the given options.
*
* @param sort must not be null.
* @return all entities sorted by the given options.
* @throws IllegalArgumentException in case the given [Sort] is null.
*/
fun findAll(sort: Sort): Flow<T>
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
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;
Expand Down Expand Up @@ -95,7 +96,7 @@ void handlesGenericTypeInReturnedCollectionCorrectly() throws SecurityException,
@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);
Expand Down Expand Up @@ -169,4 +170,8 @@ abstract class Container implements Iterable<Element> {}
interface ContainerRepository extends Repository<Container, Long> {
Container someMethod();
}

interface CompletePageableAndSortingRepository extends PagingAndSortingRepository<Container, Long> {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ interface Domain {}

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> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,27 +111,11 @@ void considersIntermediateMethodsAsFinderMethods() {
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();
Expand Down Expand Up @@ -427,4 +411,8 @@ public Sample save(Sample entity) {
return entity;
}
}

interface CompletePageableAndSortingRepository<T, ID> extends CrudRepository<T, ID>, PagingAndSortingRepository<T, ID> {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void discoversRxJava3MethodWithConvertibleArguments() throws Exception {
@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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
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;
Expand Down Expand Up @@ -47,7 +48,7 @@ class ReactiveWrapperRepositoryFactorySupportUnitTests {

DummyRepositoryFactory factory;

@Mock ReactiveSortingRepository<Object, Serializable> backingRepo;
@Mock ReactiveCrudRepository<Object, Serializable> backingRepo;
@Mock ObjectRepositoryCustom customImplementation;

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
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;
Expand Down Expand Up @@ -90,7 +91,7 @@ class RepositoryFactorySupportUnitTests {

DummyRepositoryFactory factory;

@Mock PagingAndSortingRepository<Object, Object> backingRepo;
@Mock CrudRepository<Object, Object> backingRepo;
@Mock ObjectRepositoryCustom customImplementation;

@Mock MyQueryCreationListener listener;
Expand Down Expand Up @@ -167,12 +168,11 @@ void invokesCustomMethodCompositionMethodIfItRedeclaresACRUDOne() {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ interface OrderRepository extends CrudRepository<Order, Long> {

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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ void createsCrudRepositoryInvokerForRepositoryExtendingCrudRepository() {
var invoker = factory.getInvokerFor(User.class);

assertThat(invoker)//
.isInstanceOf(CrudRepositoryInvoker.class)//
.isNotInstanceOf(PagingAndSortingRepositoryInvoker.class);
.isInstanceOf(CrudRepositoryInvoker.class);
}
}
Loading