Merge branch '6.1.x'

This commit is contained in:
Stéphane Nicoll 2024-07-10 12:39:05 +02:00
commit c6b20c04c2
3 changed files with 57 additions and 12 deletions

View File

@ -213,12 +213,13 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
if (!(executable instanceof Method method)) {
return beanSupplier.get();
}
Method priorInvokedFactoryMethod = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
try {
SimpleInstantiationStrategy.setCurrentlyInvokedFactoryMethod(method);
return beanSupplier.get();
}
finally {
SimpleInstantiationStrategy.setCurrentlyInvokedFactoryMethod(null);
SimpleInstantiationStrategy.setCurrentlyInvokedFactoryMethod(priorInvokedFactoryMethod);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@ -55,13 +55,19 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
}
/**
* Set the factory method currently being invoked or {@code null} to reset.
* Set the factory method currently being invoked or {@code null} to remove
* the current value, if any.
* @param method the factory method currently being invoked or {@code null}
* @since 6.0
*/
public static void setCurrentlyInvokedFactoryMethod(@Nullable Method method) {
if (method != null) {
currentlyInvokedFactoryMethod.set(method);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
@Override
@ -134,9 +140,9 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
try {
ReflectionUtils.makeAccessible(factoryMethod);
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
Method priorInvokedFactoryMethod = getCurrentlyInvokedFactoryMethod();
try {
currentlyInvokedFactoryMethod.set(factoryMethod);
setCurrentlyInvokedFactoryMethod(factoryMethod);
Object result = factoryMethod.invoke(factoryBean, args);
if (result == null) {
result = new NullBean();
@ -144,12 +150,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
return result;
}
finally {
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
else {
currentlyInvokedFactoryMethod.remove();
}
setCurrentlyInvokedFactoryMethod(priorInvokedFactoryMethod);
}
}
catch (IllegalArgumentException ex) {

View File

@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Stream;
@ -51,6 +52,7 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.InstanceSupplier;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.support.SimpleInstantiationStrategy;
import org.springframework.core.env.Environment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
@ -293,6 +295,33 @@ class BeanInstanceSupplierTests {
assertThat(instance).isEqualTo("1");
}
@Test // gh-33180
void getWithNestedInvocationRetainsFactoryMethod() throws Exception {
AtomicReference<Method> testMethodReference = new AtomicReference<>();
AtomicReference<Method> anotherMethodReference = new AtomicReference<>();
BeanInstanceSupplier<Object> nestedInstanceSupplier = BeanInstanceSupplier
.forFactoryMethod(AnotherTestStringFactory.class, "another")
.withGenerator(registeredBean -> {
anotherMethodReference.set(SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod());
return "Another";
});
RegisteredBean nestedRegisteredBean = new Source(String.class, nestedInstanceSupplier).registerBean(this.beanFactory);
BeanInstanceSupplier<Object> instanceSupplier = BeanInstanceSupplier
.forFactoryMethod(TestStringFactory.class, "test")
.withGenerator(registeredBean -> {
Object nested = nestedInstanceSupplier.get(nestedRegisteredBean);
testMethodReference.set(SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod());
return "custom" + nested;
});
RegisteredBean registeredBean = new Source(String.class, instanceSupplier).registerBean(this.beanFactory);
Object value = instanceSupplier.get(registeredBean);
assertThat(value).isEqualTo("customAnother");
assertThat(testMethodReference.get()).isEqualTo(instanceSupplier.getFactoryMethod());
assertThat(anotherMethodReference.get()).isEqualTo(nestedInstanceSupplier.getFactoryMethod());
}
@Test
void resolveArgumentsWithNoArgConstructor() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
@ -1031,4 +1060,18 @@ class BeanInstanceSupplierTests {
}
static class TestStringFactory {
String test() {
return "test";
}
}
static class AnotherTestStringFactory {
String another() {
return "another";
}
}
}