/*
* Copyright 2013-2017 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
*
* http://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.assertj.core.api.Assertions.*;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.junit.Test;
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.Repository;
import org.springframework.data.repository.core.CrudMethods;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
/**
* Unit tests dor {@link DefaultCrudMethods}.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class DefaultCrudMethodsUnitTests {
@Test
public void detectsMethodsOnCrudRepository() throws Exception {
Class<DomainCrudRepository> type = DomainCrudRepository.class;
assertFindAllMethodOn(type, type.getMethod("findAll"));
assertDeleteMethodOn(type, type.getMethod("delete", Object.class));
assertSaveMethodPresent(type, true);
}
@Test
public void detectsMethodsOnPagingAndSortingRepository() throws Exception {
Class<DomainPagingAndSortingRepository> type = DomainPagingAndSortingRepository.class;
assertFindAllMethodOn(type, type.getMethod("findAll", Pageable.class));
assertDeleteMethodOn(type, type.getMethod("delete", Object.class));
assertSaveMethodPresent(type, true);
}
@Test
public void detectsFindAllWithSortParameterOnSortingRepository() throws Exception {
Class<RepositoryWithCustomSortingFindAll> type = RepositoryWithCustomSortingFindAll.class;
assertFindAllMethodOn(type, type.getMethod("findAll", Sort.class));
assertSaveMethodPresent(type, false);
}
@Test // DATACMNS-393
public void selectsFindAllWithSortParameterOnRepositoryAmongUnsuitableAlternatives() throws Exception {
Class<RepositoryWithInvalidPagingFallbackToSortFindAll> type = RepositoryWithInvalidPagingFallbackToSortFindAll.class;
assertFindAllMethodOn(type, type.getMethod("findAll", Sort.class));
assertSaveMethodPresent(type, false);
}
@Test
public void detectsMethodsOnCustomRepository() throws Exception {
Class<RepositoryWithCustomSortingAndPagingFindAll> type = RepositoryWithCustomSortingAndPagingFindAll.class;
assertFindAllMethodOn(type, type.getMethod("findAll", Pageable.class));
Class<RepositoryWithIterableDeleteOnly> type1 = RepositoryWithIterableDeleteOnly.class;
assertDeleteMethodOn(type1, type1.getMethod("delete", Iterable.class));
}
@Test
public void doesNotDetectInvalidlyDeclaredMethods() throws Exception {
Class<RepositoryWithInvalidPagingFindAll> type = RepositoryWithInvalidPagingFindAll.class;
assertFindAllMethodOn(type, Optional.empty());
}
@Test // DATACMNS-393
public void detectsOverloadedMethodsCorrectly() throws Exception {
Class<RepositoryWithAllCrudMethodOverloaded> type = RepositoryWithAllCrudMethodOverloaded.class;
assertFindOneMethodOn(type, type.getDeclaredMethod("findById", Long.class));
assertDeleteMethodOn(type, type.getDeclaredMethod("deleteById", Long.class));
assertSaveMethodOn(type, type.getDeclaredMethod("save", Domain.class));
assertFindAllMethodOn(type, type.getDeclaredMethod("findAll"));
}
@Test // DATACMNS-393
public void ignoresWrongOverloadedMethods() throws Exception {
Class<RepositoryWithAllCrudMethodOverloadedWrong> type = RepositoryWithAllCrudMethodOverloadedWrong.class;
assertFindOneMethodOn(type, CrudRepository.class.getDeclaredMethod("findById", Object.class));
assertDeleteMethodOn(type, CrudRepository.class.getDeclaredMethod("delete", Object.class));
assertSaveMethodOn(type, CrudRepository.class.getDeclaredMethod("save", Object.class));
assertFindAllMethodOn(type, CrudRepository.class.getDeclaredMethod("findAll"));
}
@Test // DATACMNS-464
public void detectsCustomSaveMethod() throws Exception {
assertSaveMethodOn(RepositoryWithCustomSave.class, RepositoryWithCustomSave.class.getMethod("save", Domain.class));
}
@Test // DATACMNS-539
public void detectsOverriddenDeleteMethodForEntity() throws Exception {
assertDeleteMethodOn(RepositoryWithDeleteMethodForEntityOverloaded.class,
RepositoryWithDeleteMethodForEntityOverloaded.class.getMethod("delete", Domain.class));
}
@Test // DATACMNS-619
public void exposedMethodsAreAccessible() {
CrudMethods methods = getMethodsFor(RepositoryWithAllCrudMethodOverloaded.class);
Arrays
.asList(methods.getSaveMethod(), methods.getDeleteMethod(), methods.getFindAllMethod(),
methods.getFindOneMethod())//
.forEach(method -> assertThat(method).hasValueSatisfying(it -> assertThat(it.isAccessible()).isTrue()));
}
private static CrudMethods getMethodsFor(Class<?> repositoryInterface) {
RepositoryMetadata metadata = new DefaultRepositoryMetadata(repositoryInterface);
RepositoryInformation information = new DefaultRepositoryInformation(metadata, PagingAndSortingRepository.class,
Optional.empty());
return new DefaultCrudMethods(information);
}
private static void assertFindAllMethodOn(Class<?> type, Method method) {
assertFindAllMethodOn(type, Optional.ofNullable(method));
}
private static void assertFindAllMethodOn(Class<?> type, Optional<Method> method) {
CrudMethods methods = getMethodsFor(type);
assertThat(methods.hasFindAllMethod()).isEqualTo(method.isPresent());
assertThat(methods.getFindAllMethod()).isEqualTo(method);
}
private static void assertFindOneMethodOn(Class<?> type, Method method) {
CrudMethods methods = getMethodsFor(type);
assertThat(methods.hasFindOneMethod()).isEqualTo(method != null);
assertThat(methods.getFindOneMethod()).hasValue(method);
}
private static void assertDeleteMethodOn(Class<?> type, Method method) {
CrudMethods methods = getMethodsFor(type);
assertThat(methods.hasDelete()).isEqualTo(method != null);
assertThat(methods.getDeleteMethod()).hasValue(method);
}
private static void assertSaveMethodOn(Class<?> type, Method method) {
CrudMethods methods = getMethodsFor(type);
assertThat(methods.hasSaveMethod()).isEqualTo(method != null);
assertThat(methods.getSaveMethod()).hasValue(method);
}
private static void assertSaveMethodPresent(Class<?> type, boolean present) {
CrudMethods methods = getMethodsFor(type);
assertThat(methods.hasSaveMethod()).isEqualTo(present);
assertThat(methods.getSaveMethod().isPresent()).isEqualTo(present);
}
interface Domain {}
interface DomainCrudRepository extends CrudRepository<Domain, Long> {}
interface DomainPagingAndSortingRepository extends PagingAndSortingRepository<Domain, Long> {}
interface RepositoryWithCustomSave extends Repository<Domain, Serializable> {
Domain save(Domain domain);
}
interface RepositoryWithCustomSortingAndPagingFindAll extends Repository<Domain, Serializable> {
Iterable<Domain> findAll(Sort sort);
Iterable<Domain> findAll(Pageable pageable);
}
// DATACMNS-393
interface RepositoryWithCustomSortingFindAll extends Repository<Domain, Serializable> {
Iterable<Domain> findAll(Sort sort);
}
interface RepositoryWithInvalidPagingFindAll extends Repository<Domain, Serializable> {
Iterable<Domain> findAll(Object pageable);
}
// DATACMNS-393
interface RepositoryWithInvalidPagingFallbackToSortFindAll extends Repository<Domain, Serializable> {
Iterable<Domain> findAll(Object pageable);
Iterable<Domain> findAll(Sort sort);
}
interface RepositoryWithIterableDeleteOnly extends Repository<Domain, Serializable> {
void delete(Iterable<? extends Domain> entities);
}
// DATACMNS-393
interface RepositoryWithAllCrudMethodOverloaded extends CrudRepository<Domain, Long> {
List<Domain> findAll();
<S extends Domain> S save(S entity);
void deleteById(Long id);
Optional<Domain> findById(Long id);
}
// DATACMNS-393
interface RepositoryWithAllCrudMethodOverloadedWrong extends CrudRepository<Domain, Long> {
List<Domain> findAll(String s);
Domain save(Long entity);
void delete(String o);
Domain findById(Domain o);
}
// DATACMNS-539
interface RepositoryWithDeleteMethodForEntityOverloaded extends CrudRepository<Domain, Long> {
void delete(Domain entity);
}
}