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:
@@ -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