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:
Oliver Gierke
2015-02-24 21:08:23 +01:00
parent af2e1c50c3
commit 2d62c149bb
18 changed files with 522 additions and 79 deletions

View File

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