DATACMNS-542 - Simplified way to customize repository base class.
RepositoryFactorySupport now exposes a setRepositoryBaseClass(…) to take a custom type that instances will be created reflectively for. This removes the need for a boilerplate repository factory and FactoryBean implementation to hook custom repository base class implementations into the infrastructure. RepositoryFactorySupport now exposes a getTargetRepositoryViaReflection(…) method to allow sub-classes to create repository instances and consider customized repository base classes nonetheless. getTargetRepository(…) needs a tiny signature change which unfortunately requires imple Fixed schema registration for version 1.8 schema. Added new XSD containing a base-class attribute on the <repositories /> element to customize the repository base class via XML. Removed outdated section of how to create a custom base repository class from the reference documentation and replaced it with new simplified instructions. Deprecated usage of factory-class attribute in configuration. Point users to newly introduced way of configuring a base class directly to avoid the need for a boilerplate repository factory and factory bean implementation. DefaultRepositoryInformation now makes target class methods assignable before caching and returning them, so that they can always be invoked reflectively. Made this aspect part of the contract of RepositoryInformation.getTargetClassMethod(…).
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -54,6 +54,7 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
|
||||
private static final String NAMED_QUERIES_LOCATION = "namedQueriesLocation";
|
||||
private static final String QUERY_LOOKUP_STRATEGY = "queryLookupStrategy";
|
||||
private static final String REPOSITORY_FACTORY_BEAN_CLASS = "repositoryFactoryBeanClass";
|
||||
private static final String REPOSITORY_BASE_CLASS = "repositoryBaseClass";
|
||||
private static final String CONSIDER_NESTED_REPOSITORIES = "considerNestedRepositories";
|
||||
|
||||
private final AnnotationMetadata configMetadata;
|
||||
@@ -213,6 +214,17 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
|
||||
return attributes.getClass(REPOSITORY_FACTORY_BEAN_CLASS).getName();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationSource#getRepositoryBaseClassName()
|
||||
*/
|
||||
@Override
|
||||
public String getRepositoryBaseClassName() {
|
||||
|
||||
Class<? extends Object> repositoryBaseClass = attributes.getClass(REPOSITORY_BASE_CLASS);
|
||||
return DefaultRepositoryBaseClass.class.equals(repositoryBaseClass) ? null : repositoryBaseClass.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AnnotationAttributes} of the annotation configured.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.repository.config;
|
||||
|
||||
/**
|
||||
* Placeholder class to be used in {@code @Enable} annotation's {@code repositoryBaseClass} attribute. The configuration
|
||||
* evaluation infrastructure can use this type to find out no special repository base class was configured and apply
|
||||
* defaults.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @soundtrack Elen - Sink like a stone (Elen)
|
||||
* @since 1.11
|
||||
*/
|
||||
public final class DefaultRepositoryBaseClass {
|
||||
|
||||
private DefaultRepositoryBaseClass() {}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -150,6 +150,15 @@ public class DefaultRepositoryConfiguration<T extends RepositoryConfigurationSou
|
||||
return configurationSource.getRepositoryFactoryBeanName();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfiguration#getRepositoryBaseClassName()
|
||||
*/
|
||||
@Override
|
||||
public String getRepositoryBaseClassName() {
|
||||
return configurationSource.getRepositoryBaseClassName();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfiguration#isLazyInit()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -65,7 +65,8 @@ class RepositoryBeanDefinitionBuilder {
|
||||
this.extension = extension;
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
|
||||
this.implementationDetector = new CustomRepositoryImplementationDetector(metadataReaderFactory, environment, resourceLoader);
|
||||
this.implementationDetector = new CustomRepositoryImplementationDetector(metadataReaderFactory, environment,
|
||||
resourceLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +91,7 @@ class RepositoryBeanDefinitionBuilder {
|
||||
builder.addPropertyValue("repositoryInterface", configuration.getRepositoryInterface());
|
||||
builder.addPropertyValue("queryLookupStrategyKey", configuration.getQueryLookupStrategyKey());
|
||||
builder.addPropertyValue("lazyInit", configuration.isLazyInit());
|
||||
builder.addPropertyValue("repositoryBaseClass", configuration.getRepositoryBaseClassName());
|
||||
|
||||
NamedQueriesBeanDefinitionBuilder definitionBuilder = new NamedQueriesBeanDefinitionBuilder(
|
||||
extension.getDefaultNamedQueryLocation());
|
||||
@@ -143,6 +145,4 @@ class RepositoryBeanDefinitionBuilder {
|
||||
|
||||
return beanName;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -72,9 +72,20 @@ public interface RepositoryConfiguration<T extends RepositoryConfigurationSource
|
||||
* Returns the name of the {@link FactoryBean} class to be used to create repository instances.
|
||||
*
|
||||
* @return
|
||||
* @deprecated as of 1.11 in favor of a dedicated repository class name, see {@link #getRepositoryBaseClassName()}.
|
||||
*/
|
||||
@Deprecated
|
||||
String getRepositoryFactoryBeanName();
|
||||
|
||||
/**
|
||||
* Returns the name of the repository base class to be used or {@literal null} if the store specific defaults shall be
|
||||
* applied.
|
||||
*
|
||||
* @return
|
||||
* @since 1.11
|
||||
*/
|
||||
String getRepositoryBaseClassName();
|
||||
|
||||
/**
|
||||
* Returns the source of the {@link RepositoryConfiguration}.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -68,9 +68,21 @@ public interface RepositoryConfigurationSource {
|
||||
* Returns the name of the class of the {@link FactoryBean} to actually create repository instances.
|
||||
*
|
||||
* @return
|
||||
* @deprecated as of 1.11 in favor of using a dedicated repository base class name, see
|
||||
* {@link #getRepositoryBaseClassName()}.
|
||||
*/
|
||||
@Deprecated
|
||||
String getRepositoryFactoryBeanName();
|
||||
|
||||
/**
|
||||
* Returns the name of the repository base class to be used or {@literal null} if the store specific defaults shall be
|
||||
* applied.
|
||||
*
|
||||
* @return
|
||||
* @since 1.11
|
||||
*/
|
||||
String getRepositoryBaseClassName();
|
||||
|
||||
/**
|
||||
* Returns the source {@link BeanDefinition}s of the repository interfaces to create repository instances for.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -42,6 +42,7 @@ public class XmlRepositoryConfigurationSource extends RepositoryConfigurationSou
|
||||
private static final String NAMED_QUERIES_LOCATION = "named-queries-location";
|
||||
private static final String REPOSITORY_IMPL_POSTFIX = "repository-impl-postfix";
|
||||
private static final String REPOSITORY_FACTORY_BEAN_CLASS_NAME = "factory-class";
|
||||
private static final String REPOSITORY_BASE_CLASS_NAME = "base-class";
|
||||
private static final String CONSIDER_NESTED_REPOSITORIES = "consider-nested-repositories";
|
||||
|
||||
private final Element element;
|
||||
@@ -148,6 +149,15 @@ public class XmlRepositoryConfigurationSource extends RepositoryConfigurationSou
|
||||
return getNullDefaultedAttribute(element, REPOSITORY_FACTORY_BEAN_CLASS_NAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationSource#getRepositoryBaseClassName()
|
||||
*/
|
||||
@Override
|
||||
public String getRepositoryBaseClassName() {
|
||||
return getNullDefaultedAttribute(element, REPOSITORY_BASE_CLASS_NAME);
|
||||
}
|
||||
|
||||
private String getNullDefaultedAttribute(Element element, String attributeName) {
|
||||
String attribute = element.getAttribute(attributeName);
|
||||
return StringUtils.hasText(attribute) ? attribute : null;
|
||||
|
||||
@@ -74,9 +74,10 @@ public interface RepositoryInformation extends RepositoryMetadata {
|
||||
/**
|
||||
* Returns the target class method that is backing the given method. This can be necessary if a repository interface
|
||||
* redeclares a method of the core repository interface (e.g. for transaction behaviour customization). Returns the
|
||||
* method itself if the target class does not implement the given method.
|
||||
* method itself if the target class does not implement the given method. Implementations need to make sure the
|
||||
* {@link Method} returned can be invoked via reflection, i.e. needs to be accessible.
|
||||
*
|
||||
* @param method
|
||||
* @param method must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
Method getTargetClassMethod(Method method);
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.repository.core.support;
|
||||
|
||||
import static org.springframework.core.GenericTypeResolver.*;
|
||||
import static org.springframework.data.repository.util.ClassUtils.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -117,13 +118,20 @@ class DefaultRepositoryInformation implements RepositoryInformation {
|
||||
Method result = getTargetClassMethod(method, customImplementationClass);
|
||||
|
||||
if (!result.equals(method)) {
|
||||
methodCache.put(method, result);
|
||||
return result;
|
||||
return cacheAndReturn(method, result);
|
||||
}
|
||||
|
||||
result = getTargetClassMethod(method, repositoryBaseClass);
|
||||
methodCache.put(method, result);
|
||||
return result;
|
||||
return cacheAndReturn(method, getTargetClassMethod(method, repositoryBaseClass));
|
||||
}
|
||||
|
||||
private Method cacheAndReturn(Method key, Method value) {
|
||||
|
||||
if (value != null) {
|
||||
makeAccessible(value);
|
||||
}
|
||||
|
||||
methodCache.put(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2014 the original author or authors.
|
||||
* Copyright 2008-2015 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.
|
||||
@@ -29,11 +29,11 @@ import org.springframework.data.repository.core.EntityInformation;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.DefaultEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.DefaultEvaluationContextProvider;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -51,6 +51,7 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
|
||||
|
||||
private Key queryLookupStrategyKey;
|
||||
private Class<? extends T> repositoryInterface;
|
||||
private Class<?> repositoryBaseClass;
|
||||
private Object customImplementation;
|
||||
private NamedQueries namedQueries;
|
||||
private MappingContext<?, ?> mappingContext;
|
||||
@@ -74,6 +75,16 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
|
||||
this.repositoryInterface = repositoryInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the repository base class to be used.
|
||||
*
|
||||
* @param repositoryBaseClass the repositoryBaseClass to set, can be {@literal null}.
|
||||
* @since 1.11
|
||||
*/
|
||||
public void setRepositoryBaseClass(Class<?> repositoryBaseClass) {
|
||||
this.repositoryBaseClass = repositoryBaseClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link QueryLookupStrategy.Key} to be used.
|
||||
*
|
||||
@@ -218,6 +229,7 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
|
||||
this.factory.setNamedQueries(namedQueries);
|
||||
this.factory.setBeanClassLoader(classLoader);
|
||||
this.factory.setEvaluationContextProvider(evaluationContextProvider);
|
||||
this.factory.setRepositoryBaseClass(repositoryBaseClass);
|
||||
|
||||
this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface);
|
||||
|
||||
|
||||
@@ -15,9 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.repository.core.support;
|
||||
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -28,6 +27,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
@@ -45,6 +45,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.util.ClassUtils;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -63,6 +64,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
private final Map<RepositoryInformationCacheKey, RepositoryInformation> repositoryInformationCache = new HashMap<RepositoryInformationCacheKey, RepositoryInformation>();
|
||||
private final List<RepositoryProxyPostProcessor> postProcessors = new ArrayList<RepositoryProxyPostProcessor>();
|
||||
|
||||
private Class<?> repositoryBaseClass;
|
||||
private QueryLookupStrategy.Key queryLookupStrategyKey;
|
||||
private List<QueryCreationListener<?>> queryPostProcessors = new ArrayList<QueryCreationListener<?>>();
|
||||
private NamedQueries namedQueries = PropertiesBasedNamedQueries.EMPTY;
|
||||
@@ -113,6 +115,17 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
: evaluationContextProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the repository base class to use when creating the repository proxy. If not set, the factory will use
|
||||
* the type returned by {@link #getRepositoryBaseClass(RepositoryMetadata)} by default.
|
||||
*
|
||||
* @param repositoryBaseClass the repository base class to back the repository proxy, can be {@literal null}.
|
||||
* @since 1.11
|
||||
*/
|
||||
public void setRepositoryBaseClass(Class<?> repositoryBaseClass) {
|
||||
this.repositoryBaseClass = repositoryBaseClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link QueryCreationListener} to the factory to plug in functionality triggered right after creation of
|
||||
* {@link RepositoryQuery} instances.
|
||||
@@ -214,8 +227,10 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
return repositoryInformation;
|
||||
}
|
||||
|
||||
repositoryInformation = new DefaultRepositoryInformation(metadata, getRepositoryBaseClass(metadata),
|
||||
customImplementationClass);
|
||||
Class<?> repositoryBaseClass = this.repositoryBaseClass == null ? getRepositoryBaseClass(metadata)
|
||||
: this.repositoryBaseClass;
|
||||
|
||||
repositoryInformation = new DefaultRepositoryInformation(metadata, repositoryBaseClass, customImplementationClass);
|
||||
repositoryInformationCache.put(cacheKey, repositoryInformation);
|
||||
return repositoryInformation;
|
||||
}
|
||||
@@ -240,7 +255,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
* @param metadata
|
||||
* @return
|
||||
*/
|
||||
protected abstract Object getTargetRepository(RepositoryMetadata metadata);
|
||||
protected abstract Object getTargetRepository(RepositoryInformation metadata);
|
||||
|
||||
/**
|
||||
* Returns the base class backing the actual repository instance. Make sure
|
||||
@@ -296,6 +311,29 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a repository of the repository base class defined in the given {@link RepositoryInformation} using
|
||||
* reflection.
|
||||
*
|
||||
* @param information
|
||||
* @param constructorArguments
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final <R> R getTargetRepositoryViaReflection(RepositoryInformation information,
|
||||
Object... constructorArguments) {
|
||||
|
||||
Class<?> baseClass = information.getRepositoryBaseClass();
|
||||
Constructor<?> constructor = ReflectionUtils.findConstructor(baseClass, constructorArguments);
|
||||
|
||||
if (constructor == null) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"No suitable constructor found on %s to match the given arguments: %s", baseClass, constructorArguments));
|
||||
}
|
||||
|
||||
return (R) BeanUtils.instantiateClass(constructor, constructorArguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* This {@code MethodInterceptor} intercepts calls to methods of the custom implementation and delegates the to it if
|
||||
* configured. Furthermore it resolves method calls to finders and triggers execution of them. You can rely on having
|
||||
@@ -384,8 +422,8 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
Object[] arguments = invocation.getArguments();
|
||||
|
||||
if (isCustomMethodInvocation(invocation)) {
|
||||
|
||||
Method actualMethod = repositoryInformation.getTargetClassMethod(method);
|
||||
makeAccessible(actualMethod);
|
||||
return executeMethodOn(customImplementation, actualMethod, arguments);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.util;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
@@ -238,4 +239,56 @@ public abstract class ReflectionUtils {
|
||||
|
||||
return JAVA8_STREAM_TYPE.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a constructoron the given type that matches the given constructor arguments.
|
||||
*
|
||||
* @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 or {@literal null} if none found.
|
||||
*/
|
||||
public static Constructor<?> findConstructor(Class<?> type, Object... constructorArguments) {
|
||||
|
||||
Assert.notNull(type, "Target type must not be null!");
|
||||
Assert.notNull(constructorArguments, "Constructor arguments must not be null!");
|
||||
|
||||
for (Constructor<?> candidate : type.getDeclaredConstructors()) {
|
||||
|
||||
Class<?>[] parameterTypes = candidate.getParameterTypes();
|
||||
|
||||
if (argumentsMatch(parameterTypes, constructorArguments)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final boolean argumentsMatch(Class<?>[] parameterTypes, Object[] arguments) {
|
||||
|
||||
if (parameterTypes.length != arguments.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (Class<?> argumentType : parameterTypes) {
|
||||
|
||||
Object argument = arguments[index];
|
||||
|
||||
// Reject nulls for primitives
|
||||
if (argumentType.isPrimitive() && argument == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Type check if argument is not null
|
||||
if (argument != null && !ClassUtils.isAssignableValue(argumentType, argument)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user