From 023160fb33fc9c804e7fa2d5510e350cefe445d2 Mon Sep 17 00:00:00 2001 From: John Blum Date: Tue, 12 Apr 2022 11:15:32 -0700 Subject: [PATCH] Fix mispelling of ClassUtils.getNumberOfOccurrences(..). * Re-implement getNumberOfOccurrences(..) in terms of a Stream. * Deprecate the mispelled getNumberOfOccurences(..) method and delegate to the new getNumberOfOccurrences(..) method. * Edit Javadoc. Closes #2600. --- .../data/repository/query/QueryMethod.java | 2 +- .../data/repository/util/ClassUtils.java | 33 +++++++----- .../repository/util/ClassUtilsUnitTests.java | 54 +++++++++++++++---- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/springframework/data/repository/query/QueryMethod.java b/src/main/java/org/springframework/data/repository/query/QueryMethod.java index 621d27a68..425225b65 100644 --- a/src/main/java/org/springframework/data/repository/query/QueryMethod.java +++ b/src/main/java/org/springframework/data/repository/query/QueryMethod.java @@ -70,7 +70,7 @@ public class QueryMethod { Assert.notNull(factory, "ProjectionFactory must not be null!"); Parameters.TYPES.stream() - .filter(type -> getNumberOfOccurences(method, type) > 1) + .filter(type -> getNumberOfOccurrences(method, type) > 1) .findFirst().ifPresent(type -> { throw new IllegalStateException( String.format("Method must have only one argument of type %s! Offending method: %s", diff --git a/src/main/java/org/springframework/data/repository/util/ClassUtils.java b/src/main/java/org/springframework/data/repository/util/ClassUtils.java index 20566d316..7619c5759 100644 --- a/src/main/java/org/springframework/data/repository/util/ClassUtils.java +++ b/src/main/java/org/springframework/data/repository/util/ClassUtils.java @@ -24,6 +24,7 @@ import java.util.function.Consumer; import org.springframework.data.repository.Repository; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; @@ -104,22 +105,28 @@ public abstract class ClassUtils { } /** - * Returns the number of occurences of the given type in the given {@link Method}s parameters. - * - * @param method - * @param type - * @return + * @deprecated Use {@link #getNumberOfOccurrences(Method, Class)}. */ - public static int getNumberOfOccurences(Method method, Class type) { + @Deprecated + public static int getNumberOfOccurences(@NonNull Method method, @NonNull Class type) { + return getNumberOfOccurrences(method, type); + } - int result = 0; - for (Class clazz : method.getParameterTypes()) { - if (type.equals(clazz)) { - result++; - } - } + /** + * Returns the number of occurrences for the given {@link Method#getParameterTypes() parameter type} + * in the given {@link Method}. + * + * @param method {@link Method} to evaluate. + * @param parameterType {@link Class} of the {@link Method} parameter type to count. + * @return the number of occurrences for the given {@link Method#getParameterTypes() parameter type} + * in the given {@link Method}. + * @see java.lang.reflect.Method#getParameterTypes() + */ + public static int getNumberOfOccurrences(@NonNull Method method, @NonNull Class parameterType) { - return result; + return (int) Arrays.stream(method.getParameterTypes()) + .filter(parameterType::equals) + .count(); } /** diff --git a/src/test/java/org/springframework/data/repository/util/ClassUtilsUnitTests.java b/src/test/java/org/springframework/data/repository/util/ClassUtilsUnitTests.java index c3246ddd3..9dbcb25d4 100755 --- a/src/test/java/org/springframework/data/repository/util/ClassUtilsUnitTests.java +++ b/src/test/java/org/springframework/data/repository/util/ClassUtilsUnitTests.java @@ -15,10 +15,11 @@ */ package org.springframework.data.repository.util; -import static org.assertj.core.api.Assertions.*; -import static org.springframework.data.repository.util.ClassUtils.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import java.io.Serializable; +import java.lang.reflect.Method; import java.util.List; import java.util.Map; import java.util.concurrent.Future; @@ -26,33 +27,62 @@ import java.util.concurrent.Future; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.data.repository.Repository; import org.springframework.scheduling.annotation.Async; /** - * Unit test for {@link ClassUtils}. + * Unit tests for {@link ClassUtils}. * * @author Oliver Gierke + * @author John Blum */ class ClassUtilsUnitTests { @Test void rejectsInvalidReturnType() { - assertThatIllegalStateException().isThrownBy(() -> assertReturnTypeAssignable( + assertThatIllegalStateException().isThrownBy(() -> ClassUtils.assertReturnTypeAssignable( SomeDao.class.getMethod("findByFirstname", Pageable.class, String.class), User.class)); } @Test void determinesValidFieldsCorrectly() { - assertThat(hasProperty(User.class, "firstname")).isTrue(); - assertThat(hasProperty(User.class, "Firstname")).isTrue(); - assertThat(hasProperty(User.class, "address")).isFalse(); + assertThat(ClassUtils.hasProperty(User.class, "firstname")).isTrue(); + assertThat(ClassUtils.hasProperty(User.class, "Firstname")).isTrue(); + assertThat(ClassUtils.hasProperty(User.class, "address")).isFalse(); } @Test // DATACMNS-769 void unwrapsWrapperTypesBeforeAssignmentCheck() throws Exception { - assertReturnTypeAssignable(UserRepository.class.getMethod("findAsync", Pageable.class), Page.class); + ClassUtils.assertReturnTypeAssignable(UserRepository.class.getMethod("findAsync", Pageable.class), + Page.class); + } + + @Test + public void numberOfOccurrencesForMultipleMethodParametersOfType() throws Exception { + + Method findByAddress = AnotherDao.class.getMethod("findByAddress", Pageable.class, Pageable.class); + + assertThat(ClassUtils.getNumberOfOccurrences(findByAddress, Pageable.class)).isEqualTo(2); + } + + @Test + public void numberOfOccurrencesForNoMethodParameterOfType() throws Exception { + + Method findByAddress = AnotherDao.class.getMethod("findByAddress", Pageable.class, Pageable.class); + + assertThat(ClassUtils.getNumberOfOccurrences(findByAddress, Sort.class)).isZero(); + assertThat(ClassUtils.getNumberOfOccurrences(findByAddress, Page.class)).isZero(); + } + + @Test + public void numberOfOccurrencesForSingleMethodParameterOfType() throws Exception { + + Method findByFirstname = SomeDao.class.getMethod("findByFirstname", Pageable.class, String.class); + + assertThat(ClassUtils.getNumberOfOccurrences(findByFirstname, Pageable.class)).isOne(); + assertThat(ClassUtils.getNumberOfOccurrences(findByFirstname, String.class)).isOne(); } @SuppressWarnings("unused") @@ -66,7 +96,7 @@ class ClassUtilsUnitTests { } } - static interface UserRepository extends Repository { + interface UserRepository extends Repository { @Async Future> findAsync(Pageable pageable); @@ -81,6 +111,12 @@ class ClassUtilsUnitTests { List> anotherMethod(); } + interface AnotherDao extends Repository { + + Page findByAddress(Pageable pageableOne, Pageable pageableTwo); + + } + class GenericType { }