Avoid double proxying for @Resource @Lazy fallback autowiring

Includes refactored @Resource resolver for AOT with lazy resolution support.

Closes gh-31447
See gh-29614
This commit is contained in:
Juergen Hoeller
2023-12-12 12:39:59 +01:00
parent 6bb9775309
commit 6dcba4de2c
11 changed files with 410 additions and 457 deletions

View File

@@ -142,7 +142,7 @@ class CommonAnnotationBeanRegistrationAotContributionTests {
postProcessor.apply(registeredBean, instance);
assertThat(instance).extracting("one").isEqualTo("1");
assertThat(getSourceFile(compiled, PrivateMethodResourceSample.class))
.contains("resolveAndInvoke(");
.contains("resolveAndSet(");
});
}
@@ -160,7 +160,7 @@ class CommonAnnotationBeanRegistrationAotContributionTests {
postProcessor.apply(registeredBean, instance);
assertThat(instance).extracting("text").isEqualTo("1");
assertThat(getSourceFile(compiled, PrivateMethodResourceWithCustomNameSample.class))
.contains("resolveAndInvoke(");
.contains("resolveAndSet(");
});
}
@@ -198,7 +198,7 @@ class CommonAnnotationBeanRegistrationAotContributionTests {
postProcessor.apply(registeredBean, instance);
assertThat(instance).extracting("one").isEqualTo("1");
assertThat(getSourceFile(compiled, PackagePrivateMethodResourceFromParentSample.class))
.contains("resolveAndInvoke(");
.contains("resolveAndSet(");
});
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.context.aot;
package org.springframework.context.annotation;
import org.junit.jupiter.api.Test;
@@ -30,11 +30,11 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link ResourceFieldValueResolver}.
* Tests for {@code ResourceFieldValueResolver}.
*
* @author Stephane Nicoll
*/
class ResourceFieldValueResolverTests {
class ResourceElementResolverFieldTests {
private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@@ -43,8 +43,7 @@ class ResourceFieldValueResolverTests {
void resolveWhenFieldIsMissingThrowsException() {
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
assertThatIllegalArgumentException()
.isThrownBy(() -> ResourceFieldValueResolver.forField("missing")
.resolve(registeredBean))
.isThrownBy(() -> ResourceElementResolver.forField("missing").resolve(registeredBean))
.withMessage("No field 'missing' found on " + TestBean.class.getName());
}
@@ -53,7 +52,7 @@ class ResourceFieldValueResolverTests {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
Object resolved = ResourceFieldValueResolver.forField("one")
Object resolved = ResourceElementResolver.forField("one")
.resolve(registeredBean);
assertThat(resolved).isEqualTo("1");
}
@@ -63,8 +62,7 @@ class ResourceFieldValueResolverTests {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
Object resolved = ResourceFieldValueResolver.forField("test", "two")
.resolve(registeredBean);
Object resolved = ResourceElementResolver.forField("test", "two").resolve(registeredBean);
assertThat(resolved).isEqualTo("2");
}
@@ -72,8 +70,7 @@ class ResourceFieldValueResolverTests {
void resolveWheNoMatchFallbackOnType() {
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
Object resolved = ResourceFieldValueResolver.forField("one")
.resolve(registeredBean);
Object resolved = ResourceElementResolver.forField("one").resolve(registeredBean);
assertThat(resolved).isEqualTo("2");
}
@@ -82,9 +79,8 @@ class ResourceFieldValueResolverTests {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
assertThatThrownBy(() -> ResourceFieldValueResolver.forField("test")
.resolve(registeredBean)
).isInstanceOf(NoUniqueBeanDefinitionException.class)
assertThatThrownBy(() -> ResourceElementResolver.forField("test").resolve(registeredBean))
.isInstanceOf(NoUniqueBeanDefinitionException.class)
.hasMessageContaining(String.class.getName())
.hasMessageContaining("one").hasMessageContaining("two");
}
@@ -92,9 +88,8 @@ class ResourceFieldValueResolverTests {
@Test
void resolveWhenNoCandidateMatchingTypeThrowsException() {
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
assertThatThrownBy(() -> ResourceFieldValueResolver.forField("test")
.resolve(registeredBean)
).isInstanceOf(NoSuchBeanDefinitionException.class)
assertThatThrownBy(() -> ResourceElementResolver.forField("test").resolve(registeredBean))
.isInstanceOf(NoSuchBeanDefinitionException.class)
.hasMessageContaining(String.class.getName());
}
@@ -102,9 +97,8 @@ class ResourceFieldValueResolverTests {
void resolveWhenInvalidMatchingTypeThrowsException() {
this.beanFactory.registerSingleton("count", "counter");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
assertThatThrownBy(() -> ResourceFieldValueResolver.forField("count")
.resolve(registeredBean)
).isInstanceOf(BeanNotOfRequiredTypeException.class)
assertThatThrownBy(() -> ResourceElementResolver.forField("count").resolve(registeredBean))
.isInstanceOf(BeanNotOfRequiredTypeException.class)
.hasMessageContaining(Integer.class.getName())
.hasMessageContaining(String.class.getName());
}
@@ -114,8 +108,7 @@ class ResourceFieldValueResolverTests {
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
TestBean testBean = new TestBean();
ResourceFieldValueResolver.forField("one").resolveAndSet(registeredBean,
testBean);
ResourceElementResolver.forField("one").resolveAndSet(registeredBean, testBean);
assertThat(testBean.one).isEqualTo("1");
}
@@ -123,16 +116,16 @@ class ResourceFieldValueResolverTests {
void resolveRegistersDependantBeans() {
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
ResourceFieldValueResolver.forField("one").resolve(registeredBean);
ResourceElementResolver.forField("one").resolve(registeredBean);
assertThat(this.beanFactory.getDependentBeans("one")).containsExactly("testBean");
}
private RegisteredBean registerTestBean(DefaultListableBeanFactory beanFactory) {
beanFactory.registerBeanDefinition("testBean",
new RootBeanDefinition(TestBean.class));
beanFactory.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
return RegisteredBean.of(beanFactory, "testBean");
}
static class TestBean {
String one;
@@ -140,7 +133,6 @@ class ResourceFieldValueResolverTests {
String test;
Integer count;
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.context.aot;
package org.springframework.context.annotation;
import java.io.InputStream;
@@ -32,18 +32,19 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link ResourceMethodArgumentResolver}/
* Tests for {@code ResourceMethodArgumentResolver}.
*
* @author Stephane Nicoll
*/
class ResourceMethodArgumentResolverTests {
class ResourceElementResolverMethodTests {
private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@Test
void resolveWhenMethodIsMissingThrowsException() {
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
ResourceMethodArgumentResolver resolver = ResourceMethodArgumentResolver.forMethod("missing", InputStream.class);
ResourceElementResolver resolver = ResourceElementResolver.forMethod("missing", InputStream.class);
assertThatIllegalArgumentException()
.isThrownBy(() -> resolver.resolve(registeredBean))
.withMessage("Method 'missing' with parameter type 'java.io.InputStream' declared on %s could not be found.",
@@ -55,8 +56,7 @@ class ResourceMethodArgumentResolverTests {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
ResourceMethodArgumentResolver resolver = ResourceMethodArgumentResolver
.forMethod("setOne", String.class);
ResourceElementResolver resolver = ResourceElementResolver.forMethod("setOne", String.class);
Object resolved = resolver.resolve(registeredBean);
assertThat(resolved).isEqualTo("1");
}
@@ -66,8 +66,7 @@ class ResourceMethodArgumentResolverTests {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
Object resolved = ResourceMethodArgumentResolver.forMethod("setTest", String.class, "two")
.resolve(registeredBean);
Object resolved = ResourceElementResolver.forMethod("setTest", String.class, "two").resolve(registeredBean);
assertThat(resolved).isEqualTo("2");
}
@@ -75,8 +74,7 @@ class ResourceMethodArgumentResolverTests {
void resolveWheNoMatchFallbackOnType() {
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
Object resolved = ResourceMethodArgumentResolver.forMethod("setOne", String.class)
.resolve(registeredBean);
Object resolved = ResourceElementResolver.forMethod("setOne", String.class).resolve(registeredBean);
assertThat(resolved).isEqualTo("2");
}
@@ -85,9 +83,8 @@ class ResourceMethodArgumentResolverTests {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
assertThatThrownBy(() -> ResourceMethodArgumentResolver.forMethod("setTest", String.class)
.resolve(registeredBean)
).isInstanceOf(NoUniqueBeanDefinitionException.class)
assertThatThrownBy(() -> ResourceElementResolver.forMethod("setTest", String.class).resolve(registeredBean))
.isInstanceOf(NoUniqueBeanDefinitionException.class)
.hasMessageContaining(String.class.getName())
.hasMessageContaining("one").hasMessageContaining("two");
}
@@ -95,9 +92,8 @@ class ResourceMethodArgumentResolverTests {
@Test
void resolveWhenNoCandidateMatchingTypeThrowsException() {
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
assertThatThrownBy(() -> ResourceMethodArgumentResolver.forMethod("setTest", String.class)
.resolve(registeredBean)
).isInstanceOf(NoSuchBeanDefinitionException.class)
assertThatThrownBy(() -> ResourceElementResolver.forMethod("setTest", String.class).resolve(registeredBean))
.isInstanceOf(NoSuchBeanDefinitionException.class)
.hasMessageContaining(String.class.getName());
}
@@ -105,9 +101,8 @@ class ResourceMethodArgumentResolverTests {
void resolveWhenInvalidMatchingTypeThrowsException() {
this.beanFactory.registerSingleton("count", "counter");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
assertThatThrownBy(() -> ResourceMethodArgumentResolver.forMethod("setCount", Integer.class)
.resolve(registeredBean)
).isInstanceOf(BeanNotOfRequiredTypeException.class)
assertThatThrownBy(() -> ResourceElementResolver.forMethod("setCount", Integer.class).resolve(registeredBean))
.isInstanceOf(BeanNotOfRequiredTypeException.class)
.hasMessageContaining(Integer.class.getName())
.hasMessageContaining(String.class.getName());
}
@@ -117,8 +112,7 @@ class ResourceMethodArgumentResolverTests {
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
TestBean testBean = new TestBean();
ResourceMethodArgumentResolver.forMethod("setOne", String.class)
.resolveAndInvoke(registeredBean, testBean);
ResourceElementResolver.forMethod("setOne", String.class).resolveAndSet(registeredBean, testBean);
assertThat(testBean.one).isEqualTo("1");
}
@@ -126,13 +120,12 @@ class ResourceMethodArgumentResolverTests {
void resolveRegistersDependantBeans() {
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registeredBean = registerTestBean(this.beanFactory);
ResourceMethodArgumentResolver.forMethod("setOne", String.class).resolve(registeredBean);
ResourceElementResolver.forMethod("setOne", String.class).resolve(registeredBean);
assertThat(this.beanFactory.getDependentBeans("one")).containsExactly("testBean");
}
private RegisteredBean registerTestBean(DefaultListableBeanFactory beanFactory) {
beanFactory.registerBeanDefinition("testBean",
new RootBeanDefinition(TestBean.class));
beanFactory.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
return RegisteredBean.of(beanFactory, "testBean");
}
@@ -156,7 +149,6 @@ class ResourceMethodArgumentResolverTests {
public void setCount(Integer count) {
this.count = count;
}
}
}

View File

@@ -24,7 +24,6 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -253,7 +252,6 @@ class ApplicationContextAotGeneratorTests {
}
@Test
@Disabled("gh-31447")
void processAheadOfTimeWhenHasLazyResourceAutowiringOnField() {
testResourceAutowiringComponent(LazyResourceFieldComponent.class, (bean, generationContext) -> {
Environment environment = bean.getEnvironment();