diff --git a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java
index c8af5bd5a3..616a734750 100644
--- a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java
+++ b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java
@@ -49,7 +49,7 @@ public abstract class AbstractPersistentProperty
static {
- CAUSE_FIELD = ReflectionUtils.findRequiredField(Throwable.class, "cause");
+ CAUSE_FIELD = ReflectionUtils.getRequiredField(Throwable.class, "cause");
ASSOCIATION_TYPE = ReflectionUtils.loadIfPresent("org.jmolecules.ddd.types.Association",
AbstractPersistentProperty.class.getClassLoader());
}
diff --git a/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java b/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java
index 5e6d1868a7..97dcca56a8 100644
--- a/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java
+++ b/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java
@@ -219,7 +219,7 @@ private static TypeDescriptor getTargetTypeDescriptor(PathInformation path) {
TypeDescriptor result = descriptor == null //
? TypeDescriptor
- .nested(org.springframework.data.util.ReflectionUtils.findRequiredField(owningType, leafProperty), 0)
+ .nested(org.springframework.data.util.ReflectionUtils.getRequiredField(owningType, leafProperty), 0)
: TypeDescriptor
.nested(new Property(owningType, descriptor.getReadMethod(), descriptor.getWriteMethod(), leafProperty), 0);
diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryComponentProvider.java b/src/main/java/org/springframework/data/repository/config/RepositoryComponentProvider.java
index 7999b98268..776b57ab38 100644
--- a/src/main/java/org/springframework/data/repository/config/RepositoryComponentProvider.java
+++ b/src/main/java/org/springframework/data/repository/config/RepositoryComponentProvider.java
@@ -33,8 +33,8 @@
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.RepositoryDefinition;
-import org.springframework.data.repository.util.ClassUtils;
import org.springframework.lang.NonNull;
+import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -103,7 +103,7 @@ public void addIncludeFilter(TypeFilter includeFilter) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
- boolean isNonRepositoryInterface = !ClassUtils.isGenericRepositoryInterface(beanDefinition.getBeanClassName());
+ boolean isNonRepositoryInterface = !isGenericRepositoryInterface(beanDefinition.getBeanClassName());
boolean isTopLevelType = !beanDefinition.getMetadata().hasEnclosingClass();
boolean isConsiderNestedRepositories = isConsiderNestedRepositoryInterfaces();
@@ -150,6 +150,13 @@ public void setConsiderNestedRepositoryInterfaces(boolean considerNestedReposito
this.considerNestedRepositoryInterfaces = considerNestedRepositoryInterfaces;
}
+ /**
+ * Returns whether the given type name is a {@link Repository} interface name.
+ */
+ private static boolean isGenericRepositoryInterface(@Nullable String interfaceName) {
+ return Repository.class.getName().equals(interfaceName);
+ }
+
/**
* {@link org.springframework.core.type.filter.TypeFilter} that only matches interfaces. Thus setting this up makes
* only sense providing an interface type as {@code targetType}.
@@ -180,21 +187,19 @@ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metada
*
* @author Oliver Gierke
*/
- private static class AllTypeFilter implements TypeFilter {
-
- private final List delegates;
+ private record AllTypeFilter(List delegates) implements TypeFilter {
/**
* Creates a new {@link AllTypeFilter} to match if all the given delegates match.
*
* @param delegates must not be {@literal null}.
*/
- public AllTypeFilter(List delegates) {
+ private AllTypeFilter {
Assert.notNull(delegates, "TypeFilter deleages must not be null");
- this.delegates = delegates;
}
+ @Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java
index 21e4569135..136b9a12ad 100644
--- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java
+++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java
@@ -26,6 +26,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
@@ -51,10 +52,9 @@
import org.springframework.data.repository.core.support.AbstractRepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
-import org.springframework.data.util.ReflectionUtils;
+import org.springframework.data.util.ClassUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
import org.springframework.util.StopWatch;
/**
@@ -123,8 +123,7 @@ private static Environment defaultEnvironment(@Nullable Environment environment,
return environment;
}
- return resourceLoader instanceof EnvironmentCapable capable ? capable.getEnvironment()
- : new StandardEnvironment();
+ return resourceLoader instanceof EnvironmentCapable capable ? capable.getEnvironment() : new StandardEnvironment();
}
/**
@@ -321,19 +320,19 @@ private static ApplicationStartup getStartup(BeanDefinitionRegistry registry) {
private ResolvableType getRepositoryFactoryBeanType(RepositoryConfiguration> configuration) {
String interfaceName = configuration.getRepositoryInterface();
- ClassLoader classLoader = resourceLoader.getClassLoader() == null ? ClassUtils.getDefaultClassLoader()
+ ClassLoader classLoader = resourceLoader.getClassLoader() == null
+ ? org.springframework.util.ClassUtils.getDefaultClassLoader()
: resourceLoader.getClassLoader();
classLoader = classLoader != null ? classLoader : getClass().getClassLoader();
- Class> repositoryInterface = ReflectionUtils.loadIfPresent(interfaceName, classLoader);
+ Class> repositoryInterface = ClassUtils.loadIfPresent(interfaceName, classLoader);
if (repositoryInterface == null) {
return null;
}
- Class> factoryBean = ReflectionUtils.loadIfPresent(configuration.getRepositoryFactoryBeanClassName(),
- classLoader);
+ Class> factoryBean = ClassUtils.loadIfPresent(configuration.getRepositoryFactoryBeanClassName(), classLoader);
if (factoryBean == null) {
return null;
diff --git a/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java b/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java
index ddc85065ff..a2a2341f29 100644
--- a/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java
+++ b/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java
@@ -15,8 +15,6 @@
*/
package org.springframework.data.repository.core;
-import static org.springframework.data.repository.util.ClassUtils.*;
-
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
@@ -25,9 +23,12 @@
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.annotation.QueryAnnotation;
+import org.springframework.data.repository.Repository;
import org.springframework.data.util.Lazy;
import org.springframework.data.util.Streamable;
import org.springframework.data.util.TypeInformation;
+import org.springframework.lang.Contract;
+import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -166,8 +167,8 @@ private final DefaultQueryMethods calculateQueryMethods() {
Class> repositoryInterface = getRepositoryInterface();
return new DefaultQueryMethods(Streamable.of(Arrays.stream(repositoryInterface.getMethods())
- .map(it -> ClassUtils.getMostSpecificMethod(it, repositoryInterface))
- .filter(this::isQueryMethodCandidate)
+ .map(it -> ClassUtils.getMostSpecificMethod(it, repositoryInterface)) //
+ .filter(this::isQueryMethodCandidate) //
.toList()), calculateHasCustomMethod(repositoryInterface));
}
@@ -187,6 +188,27 @@ private final boolean calculateHasCustomMethod(Class> repositoryInterface) {
return false;
}
+ /**
+ * Returns where the given type is the {@link Repository} interface.
+ *
+ * @param ifc
+ * @return
+ */
+ private static boolean isGenericRepositoryInterface(Class> ifc) {
+ return Repository.class.equals(ifc);
+ }
+
+ /**
+ * Returns whether the given type name is a repository interface name.
+ *
+ * @param interfaceName
+ * @return
+ */
+ @Contract("null -> false")
+ public static boolean isGenericRepositoryInterface(@Nullable String interfaceName) {
+ return Repository.class.getName().equals(interfaceName);
+ }
+
/**
* Information about query methods to allow canonical computation and reuse of that information.
*
diff --git a/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java b/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java
index 9438a3fc92..966455cf44 100644
--- a/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java
+++ b/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java
@@ -27,7 +27,6 @@
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.GenericConversionService;
-import org.springframework.data.repository.util.ClassUtils;
import org.springframework.data.repository.util.QueryExecutionConverters;
import org.springframework.data.repository.util.ReactiveWrapperConverters;
import org.springframework.data.util.NullableWrapper;
@@ -67,7 +66,8 @@ class QueryExecutionResultHandler {
public static Class loadIfPresent(String type) {
try {
- return (Class) org.springframework.util.ClassUtils.forName(type, ClassUtils.class.getClassLoader());
+ return (Class) org.springframework.util.ClassUtils.forName(type,
+ QueryExecutionResultHandler.class.getClassLoader());
} catch (ClassNotFoundException | LinkageError e) {
return null;
}
diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java
index b2b1a728f6..af1c6ad71e 100644
--- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java
+++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java
@@ -17,6 +17,7 @@
import java.io.Serializable;
import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@@ -184,7 +185,7 @@ public void setNamedQueries(@Nullable NamedQueries namedQueries) {
@Override
public void setBeanClassLoader(@Nullable ClassLoader classLoader) {
- this.classLoader = classLoader == null ? org.springframework.util.ClassUtils.getDefaultClassLoader() : classLoader;
+ this.classLoader = classLoader == null ? ClassUtils.getDefaultClassLoader() : classLoader;
this.projectionFactory = createProjectionFactory();
}
@@ -429,15 +430,15 @@ public T getRepository(Class repositoryInterface, RepositoryFragments fra
if (DefaultMethodInvokingMethodInterceptor.hasDefaultMethods(repositoryInterface)) {
if (logger.isTraceEnabled()) {
- logger.trace(LogMessage.format("Register DefaultMethodInvokingMethodInterceptor for %s…", repositoryInterface.getName()));
+ logger.trace(LogMessage.format("Register DefaultMethodInvokingMethodInterceptor for %s…",
+ repositoryInterface.getName()));
}
result.addAdvice(new DefaultMethodInvokingMethodInterceptor());
}
Optional queryLookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey,
new ValueExpressionDelegate(
- new QueryMethodValueEvaluationContextAccessor(getEnvironment(), evaluationContextProvider),
- VALUE_PARSER));
+ new QueryMethodValueEvaluationContextAccessor(getEnvironment(), evaluationContextProvider), VALUE_PARSER));
result.addAdvice(new QueryExecutorMethodInterceptor(information, getProjectionFactory(), queryLookupStrategy,
namedQueries, queryPostProcessors, methodInvocationListeners));
@@ -529,7 +530,7 @@ private RepositoryInformation getRepositoryInformation(RepositoryMetadata metada
return repositoryInformationCache.computeIfAbsent(cacheKey, key -> {
- Class> baseClass = repositoryBaseClass != null ? repositoryBaseClass : getRepositoryBaseClass(metadata);
+ Class> baseClass = repositoryBaseClass != null ? repositoryBaseClass : getRepositoryBaseClass(metadata);
return new DefaultRepositoryInformation(metadata, baseClass, composition);
});
@@ -751,11 +752,13 @@ public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) thro
try {
return composition.invoke(invocationMulticaster, method, arguments);
- } catch (Exception e) {
- org.springframework.data.repository.util.ClassUtils.unwrapReflectionException(e);
- }
+ } catch (Exception ex) {
+ if (ex instanceof InvocationTargetException) {
+ throw ((InvocationTargetException) ex).getTargetException();
+ }
- throw new IllegalStateException("Should not occur");
+ throw ex;
+ }
}
}
@@ -886,25 +889,24 @@ static class RepositoryValidator {
static {
- org.springframework.data.repository.util.ClassUtils.ifPresent(
- "org.springframework.data.querydsl.QuerydslPredicateExecutor", RepositoryValidator.class.getClassLoader(),
- it -> {
+ org.springframework.data.util.ClassUtils.ifPresent("org.springframework.data.querydsl.QuerydslPredicateExecutor",
+ RepositoryValidator.class.getClassLoader(), it -> {
WELL_KNOWN_EXECUTORS.put(it, "Querydsl");
});
- org.springframework.data.repository.util.ClassUtils.ifPresent(
+ org.springframework.data.util.ClassUtils.ifPresent(
"org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor",
RepositoryValidator.class.getClassLoader(), it -> {
WELL_KNOWN_EXECUTORS.put(it, "Reactive Querydsl");
});
- org.springframework.data.repository.util.ClassUtils.ifPresent(
+ org.springframework.data.util.ClassUtils.ifPresent(
"org.springframework.data.repository.query.QueryByExampleExecutor",
RepositoryValidator.class.getClassLoader(), it -> {
WELL_KNOWN_EXECUTORS.put(it, "Query by Example");
});
- org.springframework.data.repository.util.ClassUtils.ifPresent(
+ org.springframework.data.util.ClassUtils.ifPresent(
"org.springframework.data.repository.query.ReactiveQueryByExampleExecutor",
RepositoryValidator.class.getClassLoader(), it -> {
WELL_KNOWN_EXECUTORS.put(it, "Reactive Query by Example");
diff --git a/src/main/java/org/springframework/data/repository/query/Parameter.java b/src/main/java/org/springframework/data/repository/query/Parameter.java
index 89205e16e0..97eccfbd5f 100644
--- a/src/main/java/org/springframework/data/repository/query/Parameter.java
+++ b/src/main/java/org/springframework/data/repository/query/Parameter.java
@@ -30,9 +30,9 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
-import org.springframework.data.repository.util.ClassUtils;
import org.springframework.data.repository.util.QueryExecutionConverters;
import org.springframework.data.repository.util.ReactiveWrapperConverters;
+import org.springframework.data.util.ClassUtils;
import org.springframework.data.util.Lazy;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
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 5528c3e351..5a3f887694 100644
--- a/src/main/java/org/springframework/data/repository/query/QueryMethod.java
+++ b/src/main/java/org/springframework/data/repository/query/QueryMethod.java
@@ -15,8 +15,6 @@
*/
package org.springframework.data.repository.query;
-import static org.springframework.data.repository.util.ClassUtils.*;
-
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Set;
@@ -38,6 +36,7 @@
import org.springframework.data.util.Lazy;
import org.springframework.data.util.NullableWrapperConverters;
import org.springframework.data.util.ReactiveWrappers;
+import org.springframework.data.util.ReflectionUtils;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
@@ -77,7 +76,9 @@ public QueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory
Assert.notNull(factory, "ProjectionFactory must not be null");
Parameters.TYPES.stream() //
- .filter(type -> getNumberOfOccurrences(method, type) > 1).findFirst().ifPresent(type -> {
+ .filter(type -> ReflectionUtils.getParameterCount(method, type::equals) > 1) //
+ .findFirst() //
+ .ifPresent(type -> {
throw new IllegalStateException(String.format(
"Method must have only one argument of type %s; Offending method: %s", type.getSimpleName(), method));
});
@@ -107,19 +108,19 @@ private void validate() {
QueryMethodValidator.validate(method);
- if (hasParameterOfType(method, Pageable.class)) {
+ if (ReflectionUtils.hasParameterOfType(method, Pageable.class)) {
if (!isStreamQuery()) {
assertReturnTypeAssignable(method, QueryExecutionConverters.getAllowedPageableTypes());
}
- if (hasParameterOfType(method, Sort.class)) {
+ if (ReflectionUtils.hasParameterOfType(method, Sort.class)) {
throw new IllegalStateException(String.format("Method must not have Pageable *and* Sort parameters. "
+ "Use sorting capabilities on Pageable instead; Offending method: %s", method));
}
}
- if (hasParameterOfType(method, ScrollPosition.class)) {
+ if (ReflectionUtils.hasParameterOfType(method, ScrollPosition.class)) {
assertReturnTypeAssignable(method, Collections.singleton(Window.class));
}
@@ -388,11 +389,12 @@ static void validate(Method method) {
static Predicate pageableCannotHaveSortOrLimit = (method) -> {
- if (!hasParameterAssignableToType(method, Pageable.class)) {
+ if (!ReflectionUtils.hasParameterAssignableToType(method, Pageable.class)) {
return true;
}
- if (hasParameterAssignableToType(method, Sort.class) || hasParameterAssignableToType(method, Limit.class)) {
+ if (ReflectionUtils.hasParameterAssignableToType(method, Sort.class)
+ || ReflectionUtils.hasParameterAssignableToType(method, Limit.class)) {
return false;
}
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 37fd9cad9b..a57502ed24 100644
--- a/src/main/java/org/springframework/data/repository/util/ClassUtils.java
+++ b/src/main/java/org/springframework/data/repository/util/ClassUtils.java
@@ -19,7 +19,6 @@
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
import java.util.function.Consumer;
import org.springframework.data.repository.Repository;
@@ -36,7 +35,9 @@
* @author Oliver Gierke
* @author Mark Paluch
* @author Johannes Englmeier
+ * @deprecated since 3.5, use {@link org.springframework.data.util.ClassUtils} instead.
*/
+@Deprecated(since = "3.5", forRemoval = true)
public abstract class ClassUtils {
/**
@@ -72,16 +73,7 @@ public static boolean hasProperty(Class> type, String property) {
* definition for a superclass or interface implemented by the class to be checked here)
*/
public static void ifPresent(String className, @Nullable ClassLoader classLoader, Consumer> action) {
-
- try {
- Class> theClass = org.springframework.util.ClassUtils.forName(className, classLoader);
- action.accept(theClass);
- } catch (IllegalAccessError err) {
- throw new IllegalStateException(
- "Readability mismatch in inheritance hierarchy of class [" + className + "]: " + err.getMessage(), err);
- } catch (Throwable ex) {
- // Typically ClassNotFoundException or NoClassDefFoundError...
- }
+ org.springframework.data.util.ClassUtils.ifPresent(className, classLoader, action);
}
/**
@@ -108,7 +100,6 @@ public static boolean isGenericRepositoryInterface(@Nullable String interfaceNam
/**
* @deprecated Use {@link #getNumberOfOccurrences(Method, Class)}.
*/
- @Deprecated
public static int getNumberOfOccurences(Method method, Class> type) {
return getNumberOfOccurrences(method, type);
}
@@ -124,10 +115,7 @@ public static int getNumberOfOccurences(Method method, Class> type) {
* @see java.lang.reflect.Method#getParameterTypes()
*/
public static int getNumberOfOccurrences(@NonNull Method method, @NonNull Class> parameterType) {
-
- return (int) Arrays.stream(method.getParameterTypes())
- .filter(parameterType::equals)
- .count();
+ return org.springframework.data.util.ReflectionUtils.getParameterCount(method, parameterType::equals);
}
/**
@@ -174,7 +162,7 @@ public static boolean isOfType(@Nullable Object object, Collection> typ
* @return
*/
public static boolean hasParameterOfType(Method method, Class> type) {
- return Arrays.asList(method.getParameterTypes()).contains(type);
+ return org.springframework.data.util.ReflectionUtils.hasParameterOfType(method, type);
}
/**
@@ -185,7 +173,7 @@ public static boolean hasParameterOfType(Method method, Class> type) {
* @return
*/
public static boolean hasParameterAssignableToType(Method method, Class> type) {
- return List.of(method.getParameterTypes()).stream().anyMatch(type::isAssignableFrom);
+ return org.springframework.data.util.ReflectionUtils.hasParameterOfType(method, type);
}
/**
@@ -196,8 +184,8 @@ public static boolean hasParameterAssignableToType(Method method, Class> type)
*/
public static void unwrapReflectionException(Exception ex) throws Throwable {
- if (ex instanceof InvocationTargetException) {
- throw ((InvocationTargetException) ex).getTargetException();
+ if (ex instanceof InvocationTargetException ite) {
+ ReflectionUtils.handleInvocationTargetException(ite);
}
throw ex;
diff --git a/src/main/java/org/springframework/data/spel/EvaluationContextExtensionInformation.java b/src/main/java/org/springframework/data/spel/EvaluationContextExtensionInformation.java
index c7895ebbdf..a4f79ddf23 100644
--- a/src/main/java/org/springframework/data/spel/EvaluationContextExtensionInformation.java
+++ b/src/main/java/org/springframework/data/spel/EvaluationContextExtensionInformation.java
@@ -74,7 +74,7 @@ public EvaluationContextExtensionInformation(Class extends EvaluationContextEx
Assert.notNull(type, "Extension type must not be null");
- Class> rootObjectType = org.springframework.data.util.ReflectionUtils.findRequiredMethod(type, "getRootObject")
+ Class> rootObjectType = org.springframework.data.util.ReflectionUtils.getRequiredMethod(type, "getRootObject")
.getReturnType();
this.rootObjectInformation = Optional
diff --git a/src/main/java/org/springframework/data/spel/ReactiveExtensionAwareEvaluationContextProvider.java b/src/main/java/org/springframework/data/spel/ReactiveExtensionAwareEvaluationContextProvider.java
index bdc68bfb59..65352f6e4f 100644
--- a/src/main/java/org/springframework/data/spel/ReactiveExtensionAwareEvaluationContextProvider.java
+++ b/src/main/java/org/springframework/data/spel/ReactiveExtensionAwareEvaluationContextProvider.java
@@ -139,7 +139,7 @@ private Mono> getExtensions(
private static ResolvableType getExtensionType(ExtensionIdAware extensionCandidate) {
return ResolvableType
- .forMethodReturnType(ReflectionUtils.findRequiredMethod(extensionCandidate.getClass(), "getExtension"))
+ .forMethodReturnType(ReflectionUtils.getRequiredMethod(extensionCandidate.getClass(), "getExtension"))
.getGeneric(0);
}
}
diff --git a/src/main/java/org/springframework/data/util/BeanLookup.java b/src/main/java/org/springframework/data/util/BeanLookup.java
index 3c2470d288..cf602a6ba6 100644
--- a/src/main/java/org/springframework/data/util/BeanLookup.java
+++ b/src/main/java/org/springframework/data/util/BeanLookup.java
@@ -41,7 +41,7 @@ private BeanLookup() {}
* beans of the given type are available in the given {@link BeanFactory}.
*
* @param type must not be {@literal null}.
- * @param beanFactory the {@link BeanFactory} to lookup the bean from.
+ * @param beanFactory the {@link BeanFactory} to look up the bean from.
* @return a {@link Lazy} for the unique bean of the given type or the instance provided by the fallback in case no
* bean of the given type can be found.
*/
diff --git a/src/main/java/org/springframework/data/util/CastUtils.java b/src/main/java/org/springframework/data/util/CastUtils.java
index c9df96626c..902eb8a362 100644
--- a/src/main/java/org/springframework/data/util/CastUtils.java
+++ b/src/main/java/org/springframework/data/util/CastUtils.java
@@ -15,6 +15,10 @@
*/
package org.springframework.data.util;
+/**
+ * @deprecated since 3.5 will be removed in a future release.
+ */
+@Deprecated(since = "3.5", forRemoval = true)
public interface CastUtils {
@SuppressWarnings("unchecked")
diff --git a/src/main/java/org/springframework/data/util/ClassUtils.java b/src/main/java/org/springframework/data/util/ClassUtils.java
new file mode 100644
index 0000000000..eecaf4ae2f
--- /dev/null
+++ b/src/main/java/org/springframework/data/util/ClassUtils.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2008-2024 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.util;
+
+import java.util.function.Consumer;
+
+import org.springframework.lang.Nullable;
+
+/**
+ * Utility class to work with classes.
+ *
+ * @author Oliver Gierke
+ * @author Mark Paluch
+ * @author Johannes Englmeier
+ * @since 3.5
+ */
+public abstract class ClassUtils {
+
+ /**
+ * Private constructor to prevent instantiation.
+ */
+ private ClassUtils() {}
+
+ /**
+ * Determine whether the {@link Class} identified by the supplied {@code className} is present and can be loaded and
+ * call the {@link Consumer action} if the {@link Class} could be loaded.
+ *
+ * @param className the name of the class to check.
+ * @param classLoader the class loader to use (can be {@literal null}, which indicates the default class loader).
+ * @param action the action callback to notify.
+ * @throws IllegalStateException if the corresponding class is resolvable but there was a readability mismatch in the
+ * inheritance hierarchy of the class (typically a missing dependency declaration in a Jigsaw module
+ * definition for a superclass or interface implemented by the class to be checked here)
+ */
+ public static void ifPresent(String className, @Nullable ClassLoader classLoader, Consumer> action) {
+
+ try {
+ Class> theClass = org.springframework.util.ClassUtils.forName(className, classLoader);
+ action.accept(theClass);
+ } catch (IllegalAccessError err) {
+ throw new IllegalStateException(
+ "Readability mismatch in inheritance hierarchy of class [" + className + "]: " + err.getMessage(), err);
+ } catch (Throwable ex) {
+ // Typically ClassNotFoundException or NoClassDefFoundError...
+ }
+ }
+
+ /**
+ * Loads the class with the given name using the given {@link ClassLoader}.
+ *
+ * @param name the name of the class to be loaded.
+ * @param classLoader the class loader to use (can be {@literal null}, which indicates the default class loader).
+ * @return the {@link Class} or {@literal null} in case the class can't be loaded for any reason.
+ */
+ @Nullable
+ public static Class> loadIfPresent(String name, @Nullable ClassLoader classLoader) {
+
+ try {
+ return org.springframework.util.ClassUtils.forName(name, classLoader);
+ } catch (Exception o_O) {
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/org/springframework/data/util/ReflectionUtils.java b/src/main/java/org/springframework/data/util/ReflectionUtils.java
index 2809f2ec39..fbee7fdaf4 100644
--- a/src/main/java/org/springframework/data/util/ReflectionUtils.java
+++ b/src/main/java/org/springframework/data/util/ReflectionUtils.java
@@ -19,11 +19,13 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
-import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.springframework.beans.BeanUtils;
@@ -52,6 +54,50 @@ private ReflectionUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
+ /**
+ * Returns whether the given {@link Method} has a parameter of the given type.
+ *
+ * @param method the method to check, must not be {@literal null}.
+ * @param type parameter type to query for, must not be {@literal null}.
+ * @return {@literal true} the given {@link Method} has a parameter of the given type.
+ * @since 3.5
+ */
+ public static boolean hasParameterOfType(Method method, Class> type) {
+ return Arrays.asList(method.getParameterTypes()).contains(type);
+ }
+
+ /**
+ * Returns whether the given {@link Method} has a parameter that is assignable to the given type.
+ *
+ * @param method the method to check, must not be {@literal null}.
+ * @param type parameter type to query for, must not be {@literal null}.
+ * @return {@literal true} the given {@link Method} has a parameter that is assignable to the given type.
+ * @since 3.5
+ */
+ public static boolean hasParameterAssignableToType(Method method, Class> type) {
+
+ for (Class> parameterType : method.getParameterTypes()) {
+ if (type.isAssignableFrom(parameterType)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the number of matching parameters {@link Method} for {@link Predicate}.
+ *
+ * @param method {@link Method} to evaluate.
+ * @param predicate the predicate matching {@link Method}
+ * @return the resulting number of matching parameters.
+ * @see java.lang.reflect.Method#getParameterTypes()
+ * @since 3.5
+ */
+ public static int getParameterCount(Method method, Predicate> predicate) {
+ return (int) Arrays.stream(method.getParameterTypes()).filter(predicate).count();
+ }
+
/**
* Creates an instance of the class with the given fully qualified name or returns the given default instance if the
* class cannot be loaded or instantiated.
@@ -59,8 +105,10 @@ private ReflectionUtils() {
* @param classname the fully qualified class name to create an instance for.
* @param defaultInstance the instance to fall back to in case the given class cannot be loaded or instantiated.
* @return
+ * @deprecated since 3.5 as it is not used within the framework anymore.
*/
@SuppressWarnings("unchecked")
+ @Deprecated(since = "3.5", forRemoval = true)
public static T createInstanceIfPresent(String classname, T defaultInstance) {
try {
@@ -106,6 +154,7 @@ public interface DescribedFieldFilter extends FieldFilter {
* @return
*/
String getDescription();
+
}
/**
@@ -129,6 +178,7 @@ public boolean matches(Field field) {
public String getDescription() {
return String.format("Annotation filter for %s", annotationType.getName());
}
+
}
/**
@@ -151,6 +201,7 @@ public boolean matches(Field field) {
public String getDescription() {
return String.format("FieldFilter %s", filter.toString());
}
+
}, false);
}
@@ -200,7 +251,7 @@ public static Field findField(Class> type, DescribedFieldFilter filter, boolea
return field;
}
- if (foundField != null && enforceUniqueness) {
+ if (foundField != null) {
throw new IllegalStateException(filter.getDescription());
}
@@ -218,10 +269,25 @@ public static Field findField(Class> type, DescribedFieldFilter filter, boolea
*
* @param type must not be {@literal null}.
* @param name must not be {@literal null} or empty.
- * @return
+ * @return the required field.
* @throws IllegalArgumentException in case the field can't be found.
+ * @deprecated use {@link #getRequiredField(Class, String)} instead.
*/
+ @Deprecated(since = "3.5", forRemoval = true)
public static Field findRequiredField(Class> type, String name) {
+ return getRequiredField(type, name);
+ }
+
+ /**
+ * Obtains the required field of the given name on the given type or throws {@link IllegalArgumentException} if the
+ * found could not be found.
+ *
+ * @param type must not be {@literal null}.
+ * @param name must not be {@literal null} or empty.
+ * @return the required field.
+ * @throws IllegalArgumentException in case the field can't be found.
+ */
+ public static Field getRequiredField(Class> type, String name) {
Field result = org.springframework.util.ReflectionUtils.findField(type, name);
@@ -251,7 +317,9 @@ public static void setField(Field field, Object target, @Nullable Object value)
* @param type must not be {@literal null}.
* @param constructorArguments must not be {@literal null}.
* @return a {@link Constructor} that is compatible with the given arguments.
+ * @deprecated since 3.5, return type will change to nullable instead of Optional.
*/
+ @Deprecated
public static Optional> findConstructor(Class> type, Object... constructorArguments) {
Assert.notNull(type, "Target type must not be null");
@@ -271,8 +339,25 @@ public static Optional> findConstructor(Class> type, Object...
* @param parameterTypes must not be {@literal null}.
* @return the method object.
* @throws IllegalArgumentException in case the method cannot be resolved.
+ * @deprecated since 3.5, use {@link #getRequiredMethod(Class, String, Class[])} instead.
*/
+ @Deprecated
public static Method findRequiredMethod(Class> type, String name, Class>... parameterTypes) {
+ return getRequiredMethod(type, name, parameterTypes);
+ }
+
+ /**
+ * Returns the method with the given name of the given class and parameter types. Prefers regular methods over
+ * {@link Method#isBridge() bridge} and {@link Method#isSynthetic() synthetic} ones.
+ *
+ * @param type must not be {@literal null}.
+ * @param name must not be {@literal null}.
+ * @param parameterTypes must not be {@literal null}.
+ * @return the method object.
+ * @throws IllegalArgumentException in case the method cannot be resolved.
+ * @since 3.5
+ */
+ public static Method getRequiredMethod(Class> type, String name, Class>... parameterTypes) {
Assert.notNull(type, "Class must not be null");
Assert.notNull(name, "Method name must not be null");
@@ -313,7 +398,7 @@ private static boolean hasSameParams(Method method, Class>[] paramTypes) {
* Returns a {@link Stream} of the return and parameters types of the given {@link Method}.
*
* @param method must not be {@literal null}.
- * @return
+ * @return stream of return and parameter types.
* @since 2.0
*/
public static Stream> returnTypeAndParameters(Method method) {
@@ -332,25 +417,51 @@ public static Stream> returnTypeAndParameters(Method method) {
* @param type must not be {@literal null}.
* @param name must not be {@literal null} or empty.
* @param parameterTypes must not be {@literal null}.
- * @return
+ * @return the optional Method.
* @since 2.0
*/
+ @Deprecated(since = "3.5", forRemoval = true)
public static Optional getMethod(Class> type, String name, ResolvableType... parameterTypes) {
+ return Optional.ofNullable(findMethod(type, name, parameterTypes));
+ }
+
+ /**
+ * Returns the {@link Method} with the given name and parameters declared on the given type, if available.
+ *
+ * @param type must not be {@literal null}.
+ * @param name must not be {@literal null} or empty.
+ * @param parameterTypes must not be {@literal null}.
+ * @return the required method.
+ * @since 3.5
+ */
+ @Nullable
+ public static Method findMethod(Class> type, String name, ResolvableType... parameterTypes) {
Assert.notNull(type, "Type must not be null");
Assert.hasText(name, "Name must not be null or empty");
Assert.notNull(parameterTypes, "Parameter types must not be null");
- List> collect = Arrays.stream(parameterTypes)//
- .map(ResolvableType::getRawClass)//
- .collect(Collectors.toList());
+ List> collect = parameterTypes.length == 0 ? Collections.emptyList()
+ : new ArrayList<>(parameterTypes.length);
+ for (ResolvableType parameterType : parameterTypes) {
+ Class> rawClass = parameterType.getRawClass();
+ collect.add(rawClass);
+ }
+
+ Method method = org.springframework.util.ReflectionUtils.findMethod(type, name, collect.toArray(new Class>[0]));
+
+ if (method != null) {
- Method method = org.springframework.util.ReflectionUtils.findMethod(type, name,
- collect.toArray(new Class>[collect.size()]));
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (!ResolvableType.forMethodParameter(method, i).equals(parameterTypes[i])) {
+ return null;
+ }
+ }
+
+ return method;
+ }
- return Optional.ofNullable(method)//
- .filter(it -> IntStream.range(0, it.getParameterCount())//
- .allMatch(index -> ResolvableType.forMethodParameter(it, index).equals(parameterTypes[index])));
+ return null;
}
private static boolean argumentsMatch(Class>[] parameterTypes, Object[] arguments) {
@@ -455,12 +566,9 @@ public static Object getPrimitiveDefault(Class> type) {
* @since 2.5
*/
@Nullable
+ @Deprecated(since = "3.5", forRemoval = true)
public static Class> loadIfPresent(String name, ClassLoader classLoader) {
-
- try {
- return ClassUtils.forName(name, classLoader);
- } catch (Exception o_O) {
- return null;
- }
+ return org.springframework.data.util.ClassUtils.loadIfPresent(name, classLoader);
}
+
}
diff --git a/src/test/kotlin/org/springframework/data/repository/kotlin/CoroutineRepositoryMetadataUnitTests.kt b/src/test/kotlin/org/springframework/data/repository/kotlin/CoroutineRepositoryMetadataUnitTests.kt
index 729ebb6a0b..2452494806 100644
--- a/src/test/kotlin/org/springframework/data/repository/kotlin/CoroutineRepositoryMetadataUnitTests.kt
+++ b/src/test/kotlin/org/springframework/data/repository/kotlin/CoroutineRepositoryMetadataUnitTests.kt
@@ -34,7 +34,12 @@ class CoroutineRepositoryMetadataUnitTests {
fun shouldDetermineCorrectResultType() {
val metadata = DefaultRepositoryMetadata(MyCoRepository::class.java)
- val method = ReflectionUtils.findRequiredMethod(MyCoRepository::class.java, "findOne", String::class.java, Continuation::class.java);
+ val method = ReflectionUtils.getRequiredMethod(
+ MyCoRepository::class.java,
+ "findOne",
+ String::class.java,
+ Continuation::class.java
+ );
assertThat(metadata.getReturnedDomainClass(method)).isEqualTo(User::class.java)
}
@@ -43,7 +48,12 @@ class CoroutineRepositoryMetadataUnitTests {
fun shouldDetermineCorrectOptionalResultType() {
val metadata = DefaultRepositoryMetadata(MyCoRepository::class.java)
- val method = ReflectionUtils.findRequiredMethod(MyCoRepository::class.java, "findOneOptional", String::class.java, Continuation::class.java);
+ val method = ReflectionUtils.getRequiredMethod(
+ MyCoRepository::class.java,
+ "findOneOptional",
+ String::class.java,
+ Continuation::class.java
+ );
assertThat(metadata.getReturnedDomainClass(method)).isEqualTo(User::class.java)
}
@@ -52,7 +62,11 @@ class CoroutineRepositoryMetadataUnitTests {
fun shouldDetermineCorrectFlowResultType() {
val metadata = DefaultRepositoryMetadata(MyCoRepository::class.java)
- val method = ReflectionUtils.findRequiredMethod(MyCoRepository::class.java, "findMultiple", String::class.java);
+ val method = ReflectionUtils.getRequiredMethod(
+ MyCoRepository::class.java,
+ "findMultiple",
+ String::class.java
+ );
assertThat(metadata.getReturnedDomainClass(method)).isEqualTo(User::class.java)
}
@@ -61,7 +75,12 @@ class CoroutineRepositoryMetadataUnitTests {
fun shouldDetermineCorrectSuspendedFlowResultType() {
val metadata = DefaultRepositoryMetadata(MyCoRepository::class.java)
- val method = ReflectionUtils.findRequiredMethod(MyCoRepository::class.java, "findMultipleSuspended", String::class.java, Continuation::class.java);
+ val method = ReflectionUtils.getRequiredMethod(
+ MyCoRepository::class.java,
+ "findMultipleSuspended",
+ String::class.java,
+ Continuation::class.java
+ );
assertThat(metadata.getReturnedDomainClass(method)).isEqualTo(User::class.java)
}