Revise ClassUtils and ReflectionUtils.
We deprecated `ClassUtils` in the repo.utils package and introduced a slimmer variant in o.s.d.util. Also, ReflectionUtils hosts now several methods that have been in ClassUtils along with an improved method naming (find vs. get in combination with return value semantics). CastUtils is deprecated as we do not widely use it.
This commit is contained in:
@@ -49,7 +49,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ public class QuerydslPredicateBuilder {
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ import org.springframework.core.type.filter.TypeFilter;
|
||||
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 @@ class RepositoryComponentProvider extends ClassPathScanningCandidateComponentPro
|
||||
@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 @@ class RepositoryComponentProvider extends ClassPathScanningCandidateComponentPro
|
||||
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 @@ class RepositoryComponentProvider extends ClassPathScanningCandidateComponentPro
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class AllTypeFilter implements TypeFilter {
|
||||
|
||||
private final List<TypeFilter> delegates;
|
||||
private record AllTypeFilter(List<TypeFilter> 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<TypeFilter> 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 {
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
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.RepositoryMetadata;
|
||||
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 @@ public class RepositoryConfigurationDelegate {
|
||||
return environment;
|
||||
}
|
||||
|
||||
return resourceLoader instanceof EnvironmentCapable capable ? capable.getEnvironment()
|
||||
: new StandardEnvironment();
|
||||
return resourceLoader instanceof EnvironmentCapable capable ? capable.getEnvironment() : new StandardEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,19 +320,19 @@ public class RepositoryConfigurationDelegate {
|
||||
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;
|
||||
|
||||
@@ -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 java.util.function.Supplier;
|
||||
|
||||
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 @@ public abstract class RepositoryInformationSupport implements RepositoryInformat
|
||||
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 @@ public abstract class RepositoryInformationSupport implements RepositoryInformat
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.springframework.core.MethodParameter;
|
||||
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 <T> Class<T> loadIfPresent(String type) {
|
||||
|
||||
try {
|
||||
return (Class<T>) org.springframework.util.ClassUtils.forName(type, ClassUtils.class.getClassLoader());
|
||||
return (Class<T>) org.springframework.util.ClassUtils.forName(type,
|
||||
QueryExecutionResultHandler.class.getClassLoader());
|
||||
} catch (ClassNotFoundException | LinkageError e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.repository.core.support;
|
||||
|
||||
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 abstract class RepositoryFactorySupport
|
||||
|
||||
@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 abstract class RepositoryFactorySupport
|
||||
|
||||
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> 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 @@ public abstract class RepositoryFactorySupport
|
||||
|
||||
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 abstract class RepositoryFactorySupport
|
||||
|
||||
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 @@ public abstract class RepositoryFactorySupport
|
||||
|
||||
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");
|
||||
|
||||
@@ -30,9 +30,9 @@ import org.springframework.data.domain.Limit;
|
||||
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;
|
||||
|
||||
@@ -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.repository.util.ReactiveWrapperConverters;
|
||||
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 class QueryMethod {
|
||||
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 @@ public class QueryMethod {
|
||||
|
||||
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 @@ public class QueryMethod {
|
||||
|
||||
static Predicate<Method> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import java.lang.reflect.InvocationTargetException;
|
||||
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 @@ import org.springframework.util.StringUtils;
|
||||
* @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 abstract class ClassUtils {
|
||||
* definition for a superclass or interface implemented by the class to be checked here)
|
||||
*/
|
||||
public static void ifPresent(String className, @Nullable ClassLoader classLoader, Consumer<Class<?>> 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 abstract class ClassUtils {
|
||||
/**
|
||||
* @deprecated Use {@link #getNumberOfOccurrences(Method, Class)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static int getNumberOfOccurences(Method method, Class<?> type) {
|
||||
return getNumberOfOccurrences(method, type);
|
||||
}
|
||||
@@ -124,10 +115,7 @@ public abstract class ClassUtils {
|
||||
* @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 abstract class ClassUtils {
|
||||
* @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 abstract class ClassUtils {
|
||||
* @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 abstract class ClassUtils {
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -74,7 +74,7 @@ class EvaluationContextExtensionInformation {
|
||||
|
||||
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
|
||||
|
||||
@@ -139,7 +139,7 @@ public class ReactiveExtensionAwareEvaluationContextProvider implements Reactive
|
||||
private static ResolvableType getExtensionType(ExtensionIdAware extensionCandidate) {
|
||||
|
||||
return ResolvableType
|
||||
.forMethodReturnType(ReflectionUtils.findRequiredMethod(extensionCandidate.getClass(), "getExtension"))
|
||||
.forMethodReturnType(ReflectionUtils.getRequiredMethod(extensionCandidate.getClass(), "getExtension"))
|
||||
.getGeneric(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public abstract class 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.
|
||||
*/
|
||||
|
||||
@@ -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")
|
||||
|
||||
78
src/main/java/org/springframework/data/util/ClassUtils.java
Normal file
78
src/main/java/org/springframework/data/util/ClassUtils.java
Normal file
@@ -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<Class<?>> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,11 +19,13 @@ import java.lang.annotation.Annotation;
|
||||
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 @@ public final class 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<Class<?>> 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 @@ public final class 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> T createInstanceIfPresent(String classname, T defaultInstance) {
|
||||
|
||||
try {
|
||||
@@ -106,6 +154,7 @@ public final class ReflectionUtils {
|
||||
* @return
|
||||
*/
|
||||
String getDescription();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,6 +178,7 @@ public final class ReflectionUtils {
|
||||
public String getDescription() {
|
||||
return String.format("Annotation filter for %s", annotationType.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,6 +201,7 @@ public final class ReflectionUtils {
|
||||
public String getDescription() {
|
||||
return String.format("FieldFilter %s", filter.toString());
|
||||
}
|
||||
|
||||
}, false);
|
||||
}
|
||||
|
||||
@@ -200,7 +251,7 @@ public final class ReflectionUtils {
|
||||
return field;
|
||||
}
|
||||
|
||||
if (foundField != null && enforceUniqueness) {
|
||||
if (foundField != null) {
|
||||
throw new IllegalStateException(filter.getDescription());
|
||||
}
|
||||
|
||||
@@ -218,10 +269,25 @@ public final class ReflectionUtils {
|
||||
*
|
||||
* @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 findRequiredField(Class<?> type, String name) {
|
||||
public static Field getRequiredField(Class<?> type, String name) {
|
||||
|
||||
Field result = org.springframework.util.ReflectionUtils.findField(type, name);
|
||||
|
||||
@@ -251,7 +317,9 @@ public final class ReflectionUtils {
|
||||
* @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<Constructor<?>> findConstructor(Class<?> type, Object... constructorArguments) {
|
||||
|
||||
Assert.notNull(type, "Target type must not be null");
|
||||
@@ -271,8 +339,25 @@ public final class ReflectionUtils {
|
||||
* @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 @@ public final class ReflectionUtils {
|
||||
* 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<Class<?>> returnTypeAndParameters(Method method) {
|
||||
@@ -332,25 +417,51 @@ public final class ReflectionUtils {
|
||||
* @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<Method> 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<Class<?>> collect = Arrays.stream(parameterTypes)//
|
||||
.map(ResolvableType::getRawClass)//
|
||||
.collect(Collectors.toList());
|
||||
List<Class<?>> 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<?>[collect.size()]));
|
||||
Method method = org.springframework.util.ReflectionUtils.findMethod(type, name, collect.toArray(new Class<?>[0]));
|
||||
|
||||
return Optional.ofNullable(method)//
|
||||
.filter(it -> IntStream.range(0, it.getParameterCount())//
|
||||
.allMatch(index -> ResolvableType.forMethodParameter(it, index).equals(parameterTypes[index])));
|
||||
if (method != null) {
|
||||
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
if (!ResolvableType.forMethodParameter(method, i).equals(parameterTypes[i])) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean argumentsMatch(Class<?>[] parameterTypes, Object[] arguments) {
|
||||
@@ -455,12 +566,9 @@ public final class ReflectionUtils {
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user