Skip to content

Commit

Permalink
Revise ClassUtils and ReflectionUtils.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mp911de committed Nov 20, 2024
1 parent 587cd70 commit 771347b
Show file tree
Hide file tree
Showing 17 changed files with 320 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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}.
Expand Down Expand Up @@ -180,21 +187,19 @@ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metada
*
* @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 {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

/**
Expand Down Expand Up @@ -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();
}

/**
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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));
}

Expand All @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -429,15 +430,15 @@ public <T> T getRepository(Class<T> 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> 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));

Expand Down Expand Up @@ -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);
});
Expand Down Expand Up @@ -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;
}
}
}

Expand Down Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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));
});
Expand Down Expand Up @@ -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));
}

Expand Down Expand Up @@ -388,11 +389,12 @@ static void validate(Method method) {

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

Expand Down
Loading

0 comments on commit 771347b

Please sign in to comment.