From 0d4fb6073dd3d80469035e91be5cf739d3f14cf6 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 27 Apr 2021 10:32:15 +0200 Subject: [PATCH] Introduce instantiateClass as replacement for RepositoryFactorySupport.getTargetRepositoryViaReflection. getTargetRepositoryViaReflection accepting Class has a misleading name as it lets assume that the returned instance is a repository. In fact, this method looks up a matching constructor for the given arguments and creates an instance. Closes #2361 --- .../support/RepositoryFactorySupport.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java index 561df1ca8..1d6bb9bf6 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java @@ -525,7 +525,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, Object... constructorArguments) { Class baseClass = information.getRepositoryBaseClass(); - return getTargetRepositoryViaReflection(baseClass, constructorArguments); + return instantiateClass(baseClass, constructorArguments); } /** @@ -535,15 +535,36 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, * @param baseClass * @param constructorArguments * @return + * @deprecated since 2.6 because it has a misleading name. Use {@link #instantiateClass(Class, Object...)} instead. */ @SuppressWarnings("unchecked") + @Deprecated protected final R getTargetRepositoryViaReflection(Class baseClass, Object... constructorArguments) { + return instantiateClass(baseClass, constructorArguments); + } + + /** + * Convenience method to instantiate a class using the given {@code constructorArguments} by looking up a matching + * constructor. + *

+ * Note that this method tries to set the constructor accessible if given a non-accessible (that is, non-public) + * constructor, and supports Kotlin classes with optional parameters and default values. + * + * @param baseClass + * @param constructorArguments + * @return + * @since 2.6 + */ + @SuppressWarnings("unchecked") + protected final R instantiateClass(Class baseClass, Object... constructorArguments) { + Optional> constructor = ReflectionUtils.findConstructor(baseClass, constructorArguments); return constructor.map(it -> (R) BeanUtils.instantiateClass(it, constructorArguments)) .orElseThrow(() -> new IllegalStateException(String.format( "No suitable constructor found on %s to match the given arguments: %s. Make sure you implement a constructor taking these", - baseClass, Arrays.stream(constructorArguments).map(Object::getClass).collect(Collectors.toList())))); + baseClass, Arrays.stream(constructorArguments).map(Object::getClass).map(ClassUtils::getQualifiedName) + .collect(Collectors.joining(", "))))); } private ApplicationStartup getStartup() {