diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/AotFactoriesLoader.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/AotFactoriesLoader.java index a57134b3bc1..a3f1f2051f5 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/AotFactoriesLoader.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/AotFactoriesLoader.java @@ -30,8 +30,8 @@ import org.springframework.util.Assert; /** * AOT specific factory loading mechanism for internal use within the framework. - *

- * Loads and instantiates factories of a given type from + * + *

Loads and instantiates factories of a given type from * {@value #FACTORIES_RESOURCE_LOCATION} and merges them with matching beans * from a {@link ListableBeanFactory}. * diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/AotFactoriesLoaderTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/AotFactoriesLoaderTests.java index d252a3663ed..19b1b3c80a0 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/AotFactoriesLoaderTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/AotFactoriesLoaderTests.java @@ -56,22 +56,14 @@ class AotFactoriesLoaderTests { beanFactory.registerSingleton("b1", new TestFactoryImpl(0, "b1")); beanFactory.registerSingleton("b2", new TestFactoryImpl(2, "b2")); MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader(); - springFactoriesLoader.addInstance(TestFactory.class, - new TestFactoryImpl(1, "l1")); - springFactoriesLoader.addInstance(TestFactory.class, - new TestFactoryImpl(3, "l2")); - AotFactoriesLoader loader = new AotFactoriesLoader(beanFactory, - springFactoriesLoader); + springFactoriesLoader.addInstance(TestFactory.class, new TestFactoryImpl(1, "l1")); + springFactoriesLoader.addInstance(TestFactory.class, new TestFactoryImpl(3, "l2")); + AotFactoriesLoader loader = new AotFactoriesLoader(beanFactory, springFactoriesLoader); List loaded = loader.load(TestFactory.class); - assertThat(loaded).hasSize(4); - assertThat(loaded.get(0)).hasToString("b1"); - assertThat(loaded.get(1)).hasToString("l1"); - assertThat(loaded.get(2)).hasToString("b2"); - assertThat(loaded.get(3)).hasToString("l2"); + assertThat(loaded).map(Object::toString).containsExactly("b1", "l1", "b2", "l2"); } - static interface TestFactory { - + interface TestFactory { } static class TestFactoryImpl implements TestFactory, Ordered { diff --git a/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java b/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java index dc2a952b065..aca3464a7fd 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java @@ -18,7 +18,6 @@ package org.springframework.core.io.support; import java.io.IOException; import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; @@ -69,15 +68,16 @@ import org.springframework.util.StringUtils; * * where {@code example.MyService} is the name of the interface, and {@code MyServiceImpl1} * and {@code MyServiceImpl2} are two implementations. - *

- * Implementation classes must have a single resolvable constructor that will + * + *

Implementation classes must have a single resolvable constructor that will * be used to create the instance, either: *

- * If the resolvable constructor has arguments, a suitable {@link ArgumentResolver + * + *

If the resolvable constructor has arguments, a suitable {@link ArgumentResolver * ArgumentResolver} should be provided. To customize how instantiation failures * are handled, consider providing a {@link FailureHandler FailureHandler}. * @@ -223,7 +223,7 @@ public class SpringFactoriesLoader { try { Class factoryImplementationClass = ClassUtils.forName(implementationName, this.classLoader); Assert.isTrue(type.isAssignableFrom(factoryImplementationClass), - () -> "Class [" + implementationName + "] is not assignable to factory type [" + type.getName() + "]"); + () -> "Class [%s] is not assignable to factory type [%s]".formatted(implementationName, type.getName())); FactoryInstantiator factoryInstantiator = FactoryInstantiator.forClass(factoryImplementationClass); return factoryInstantiator.instantiate(argumentResolver); } @@ -319,20 +319,12 @@ public class SpringFactoriesLoader { */ public static SpringFactoriesLoader forResourceLocation(@Nullable ClassLoader classLoader, String resourceLocation) { Assert.hasText(resourceLocation, "'resourceLocation' must not be empty"); - ClassLoader resourceClassLoader = (classLoader != null) ? classLoader - : SpringFactoriesLoader.class.getClassLoader(); - Map loaders = SpringFactoriesLoader.cache.get(resourceClassLoader); - if (loaders == null) { - loaders = new ConcurrentReferenceHashMap<>(); - SpringFactoriesLoader.cache.put(resourceClassLoader, loaders); - } - SpringFactoriesLoader loader = loaders.get(resourceLocation); - if (loader == null) { - Map> factories = loadFactoriesResource(resourceClassLoader, resourceLocation); - loader = new SpringFactoriesLoader(classLoader, factories); - loaders.put(resourceLocation, loader); - } - return loader; + ClassLoader resourceClassLoader = (classLoader != null ? classLoader : + SpringFactoriesLoader.class.getClassLoader()); + Map loaders = SpringFactoriesLoader.cache.computeIfAbsent( + resourceClassLoader, key -> new ConcurrentReferenceHashMap<>()); + return loaders.computeIfAbsent(resourceLocation, key -> + new SpringFactoriesLoader(classLoader, loadFactoriesResource(resourceClassLoader, resourceLocation))); } static Map> loadFactoriesResource(ClassLoader classLoader, String resourceLocation) { @@ -394,7 +386,8 @@ public class SpringFactoriesLoader { @SuppressWarnings("unchecked") static FactoryInstantiator forClass(Class factoryImplementationClass) { Constructor constructor = findConstructor(factoryImplementationClass); - Assert.state(constructor != null, "Class [" + factoryImplementationClass.getName() + "] has no suitable constructor"); + Assert.state(constructor != null, () -> + "Class [%s] has no suitable constructor".formatted(factoryImplementationClass.getName())); return new FactoryInstantiator<>((Constructor) constructor); } @@ -413,8 +406,8 @@ public class SpringFactoriesLoader { @Nullable private static Constructor findPrimaryKotlinConstructor(Class factoryImplementationClass) { - return (isKotlinType(factoryImplementationClass) - ? KotlinDelegate.findPrimaryConstructor(factoryImplementationClass) : null); + return (isKotlinType(factoryImplementationClass) ? + KotlinDelegate.findPrimaryConstructor(factoryImplementationClass) : null); } private static boolean isKotlinType(Class factoryImplementationClass) { @@ -440,12 +433,12 @@ public class SpringFactoriesLoader { /** - * Inner class to avoid a hard dependency on Kotlin at runtime. + * Nested class to avoid a hard dependency on Kotlin at runtime. */ private static class KotlinDelegate { @Nullable - public static Constructor findPrimaryConstructor(Class clazz) { + static Constructor findPrimaryConstructor(Class clazz) { try { KFunction primaryConstructor = KClasses.getPrimaryConstructor(JvmClassMappingKt.getKotlinClass(clazz)); if (primaryConstructor != null) { @@ -462,8 +455,7 @@ public class SpringFactoriesLoader { return null; } - public static T instantiate(Constructor constructor, Object[] args) - throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + static T instantiate(Constructor constructor, Object[] args) throws Exception { KFunction kotlinConstructor = ReflectJvmMapping.getKotlinFunction(constructor); if (kotlinConstructor == null) { return constructor.newInstance(args); @@ -483,7 +475,7 @@ public class SpringFactoriesLoader { private static Map convertArgs(Object[] args, List parameters) { Map result = CollectionUtils.newHashMap(parameters.size()); Assert.isTrue(args.length <= parameters.size(), - "Number of provided arguments should be less of equals than number of constructor parameters"); + "Number of provided arguments should be less than or equal to the number of constructor parameters"); for (int i = 0; i < args.length; i++) { if (!parameters.get(i).isOptional() || args[i] != null) { result.put(parameters.get(i), args[i]); @@ -552,12 +544,12 @@ public class SpringFactoriesLoader { default ArgumentResolver and(ArgumentResolver argumentResolver) { return from(type -> { Object resolved = resolve(type); - return (resolved != null) ? resolved : argumentResolver.resolve(type); + return (resolved != null ? resolved : argumentResolver.resolve(type)); }); } /** - * Factory method that returns a {@link ArgumentResolver} that always + * Factory method that returns an {@link ArgumentResolver} that always * returns {@code null}. * @return a new {@link ArgumentResolver} instance */ @@ -566,7 +558,7 @@ public class SpringFactoriesLoader { } /** - * Factory method that can be used to create a {@link ArgumentResolver} + * Factory method that can be used to create an {@link ArgumentResolver} * that resolves only the given type. * @param the argument type * @param type the argument type @@ -578,7 +570,7 @@ public class SpringFactoriesLoader { } /** - * Factory method that can be used to create a {@link ArgumentResolver} + * Factory method that can be used to create an {@link ArgumentResolver} * that resolves only the given type. * @param the argument type * @param type the argument type @@ -643,8 +635,8 @@ public class SpringFactoriesLoader { } /** - * Return a new {@link FailureHandler} that handles - * errors by throwing an exception. + * Return a new {@link FailureHandler} that handles errors by throwing an + * exception. * @param exceptionFactory factory used to create the exception * @return a new {@link FailureHandler} instance */ @@ -655,8 +647,8 @@ public class SpringFactoriesLoader { } /** - * Return a new {@link FailureHandler} that handles - * errors by logging trace messages. + * Return a new {@link FailureHandler} that handles errors by logging trace + * messages. * @param logger the logger used to log message * @return a new {@link FailureHandler} instance */ @@ -665,15 +657,15 @@ public class SpringFactoriesLoader { } /** - * Return a new {@link FailureHandler} that handles - * errors with using a standard formatted message. + * Return a new {@link FailureHandler} that handles errors using a standard + * formatted message. * @param messageHandler the message handler used to handle the problem * @return a new {@link FailureHandler} instance */ static FailureHandler handleMessage(BiConsumer, Throwable> messageHandler) { return (factoryType, factoryImplementationName, failure) -> { - Supplier message = () -> "Unable to instantiate factory class [" + factoryImplementationName + - "] for factory type [" + factoryType.getName() + "]"; + Supplier message = () -> "Unable to instantiate factory class [%s] for factory type [%s]" + .formatted(factoryImplementationName, factoryType.getName()); messageHandler.accept(message, failure); }; } diff --git a/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoaderRuntimeHintsRegistrar.java b/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoaderRuntimeHintsRegistrar.java index 185d465cae2..1e0d3f38088 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoaderRuntimeHintsRegistrar.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoaderRuntimeHintsRegistrar.java @@ -41,11 +41,11 @@ import org.springframework.util.ClassUtils; */ class SpringFactoriesLoaderRuntimeHintsRegistrar implements RuntimeHintsRegistrar { - private static List RESOURCE_LOCATIONS = List - .of(SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION); + private static List RESOURCE_LOCATIONS = + List.of(SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION); - private static final Consumer HINT = builder -> builder - .withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + private static final Consumer HINT = builder -> + builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); private final Log logger = LogFactory.getLog(SpringFactoriesLoaderRuntimeHintsRegistrar.class); @@ -57,11 +57,10 @@ class SpringFactoriesLoaderRuntimeHintsRegistrar implements RuntimeHintsRegistra } } - private void registerHints(RuntimeHints hints, ClassLoader classLoader, - String resourceLocation) { + private void registerHints(RuntimeHints hints, ClassLoader classLoader, String resourceLocation) { hints.resources().registerPattern(resourceLocation); - Map> factories = SpringFactoriesLoader - .loadFactoriesResource(classLoader, resourceLocation); + Map> factories = + SpringFactoriesLoader.loadFactoriesResource(classLoader, resourceLocation); factories.forEach((factoryClassName, implementationClassNames) -> registerHints(hints, classLoader, factoryClassName, implementationClassNames)); } @@ -69,7 +68,7 @@ class SpringFactoriesLoaderRuntimeHintsRegistrar implements RuntimeHintsRegistra private void registerHints(RuntimeHints hints, ClassLoader classLoader, String factoryClassName, List implementationClassNames) { Class factoryClass = resolveClassName(classLoader, factoryClassName); - if(factoryClass == null) { + if (factoryClass == null) { if (logger.isTraceEnabled()) { logger.trace(LogMessage.format("Skipping factories for [%s]", factoryClassName)); } @@ -83,7 +82,8 @@ class SpringFactoriesLoaderRuntimeHintsRegistrar implements RuntimeHintsRegistra Class implementationType = resolveClassName(classLoader, implementationClassName); if (logger.isTraceEnabled()) { logger.trace(LogMessage.format("%s factory type [%s] and implementation [%s]", - (implementationType != null) ? "Processing" : "Skipping", factoryClassName, implementationClassName)); + (implementationType != null ? "Processing" : "Skipping"), factoryClassName, + implementationClassName)); } if (implementationType != null) { hints.reflection().registerType(implementationType, HINT);