Resolve AOT factory method target by bean name and reduce reflective method exposure

Includes consistent withShortcut naming and consistent bean definition flag exposure.
Removes support for inner classes in alignment with standard core container behavior.

Closes gh-32834
This commit is contained in:
Juergen Hoeller
2024-09-24 18:59:08 +02:00
parent aef5143642
commit d6e4bd7c90
12 changed files with 494 additions and 584 deletions

View File

@@ -122,7 +122,7 @@ class InstanceSupplierCodeGeneratorTests {
NoDependencyComponent bean = getBean(beanDefinition, instanceSupplier);
assertThat(bean).isInstanceOf(NoDependencyComponent.class);
assertThat(compiled.getSourceFile()).contains(
"getBeanFactory().getBean(InnerComponentConfiguration.class).new NoDependencyComponent()");
"InstanceSupplier.using(InnerComponentConfiguration.NoDependencyComponent::new");
});
assertThat(getReflectionHints().getTypeHint(NoDependencyComponent.class))
.satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT));
@@ -137,7 +137,7 @@ class InstanceSupplierCodeGeneratorTests {
EnvironmentAwareComponent bean = getBean(beanDefinition, instanceSupplier);
assertThat(bean).isInstanceOf(EnvironmentAwareComponent.class);
assertThat(compiled.getSourceFile()).contains(
"getBeanFactory().getBean(InnerComponentConfiguration.class).new EnvironmentAwareComponent(");
"new InnerComponentConfiguration.EnvironmentAwareComponent(");
});
assertThat(getReflectionHints().getTypeHint(EnvironmentAwareComponent.class))
.satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT));
@@ -182,7 +182,7 @@ class InstanceSupplierCodeGeneratorTests {
assertThat(bean).isInstanceOf(String.class);
assertThat(bean).isEqualTo("Hello");
assertThat(compiled.getSourceFile()).contains(
"getBeanFactory().getBean(SimpleConfiguration.class).stringBean()");
"getBeanFactory().getBean(\"config\", SimpleConfiguration.class).stringBean()");
});
assertThat(getReflectionHints().getTypeHint(SimpleConfiguration.class))
.satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT));
@@ -199,7 +199,7 @@ class InstanceSupplierCodeGeneratorTests {
Object bean = getBean(beanDefinition, instanceSupplier);
assertThat(bean).isInstanceOf(SimpleBean.class);
assertThat(compiled.getSourceFile()).contains(
"getBeanFactory().getBean(DefaultSimpleBeanContract.class).simpleBean()");
"getBeanFactory().getBean(\"config\", DefaultSimpleBeanContract.class).simpleBean()");
});
assertThat(getReflectionHints().getTypeHint(SimpleBeanContract.class))
.satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT));
@@ -228,10 +228,8 @@ class InstanceSupplierCodeGeneratorTests {
@Test
void generateWhenHasStaticFactoryMethodWithNoArg() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(Integer.class)
.setFactoryMethodOnBean("integerBean", "config").getBeanDefinition();
this.beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(SimpleConfiguration.class).getBeanDefinition());
.rootBeanDefinition(SimpleConfiguration.class)
.setFactoryMethod("integerBean").getBeanDefinition();
compile(beanDefinition, (instanceSupplier, compiled) -> {
Integer bean = getBean(beanDefinition, instanceSupplier);
assertThat(bean).isInstanceOf(Integer.class);
@@ -246,12 +244,10 @@ class InstanceSupplierCodeGeneratorTests {
@Test
void generateWhenHasStaticFactoryMethodWithArg() {
RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(String.class)
.setFactoryMethodOnBean("create", "config").getBeanDefinition();
.rootBeanDefinition(SimpleConfiguration.class)
.setFactoryMethod("create").getBeanDefinition();
beanDefinition.setResolvedFactoryMethod(ReflectionUtils
.findMethod(SampleFactory.class, "create", Number.class, String.class));
this.beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(SampleFactory.class).getBeanDefinition());
this.beanFactory.registerSingleton("number", 42);
this.beanFactory.registerSingleton("string", "test");
compile(beanDefinition, (instanceSupplier, compiled) -> {
@@ -265,7 +261,7 @@ class InstanceSupplierCodeGeneratorTests {
}
@Test
void generateWhenHasStaticFactoryMethodCheckedException() {
void generateWhenHasFactoryMethodCheckedException() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(Integer.class)
.setFactoryMethodOnBean("throwingIntegerBean", "config")
@@ -282,107 +278,6 @@ class InstanceSupplierCodeGeneratorTests {
.satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT));
}
@Nested
@SuppressWarnings("deprecation")
class DeprecationTests {
private static final TestCompiler TEST_COMPILER = TestCompiler.forSystem()
.withCompilerOptions("-Xlint:all", "-Xlint:-rawtypes", "-Werror");
@Test
@Disabled("Need to move to a separate method so that the warning can be suppressed")
void generateWhenTargetClassIsDeprecated() {
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedBean.class));
}
@Test
void generateWhenTargetConstructorIsDeprecated() {
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedConstructor.class));
}
@Test
void generateWhenTargetFactoryMethodIsDeprecated() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(String.class)
.setFactoryMethodOnBean("deprecatedString", "config").getBeanDefinition();
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
compileAndCheckWarnings(beanDefinition);
}
@Test
void generateWhenTargetFactoryMethodParameterIsDeprecated() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(String.class)
.setFactoryMethodOnBean("deprecatedParameter", "config").getBeanDefinition();
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
beanFactory.registerBeanDefinition("parameter", new RootBeanDefinition(DeprecatedBean.class));
compileAndCheckWarnings(beanDefinition);
}
@Test
void generateWhenTargetFactoryMethodReturnTypeIsDeprecated() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(DeprecatedBean.class)
.setFactoryMethodOnBean("deprecatedReturnType", "config").getBeanDefinition();
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
compileAndCheckWarnings(beanDefinition);
}
private void compileAndCheckWarnings(BeanDefinition beanDefinition) {
assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, beanDefinition,
((instanceSupplier, compiled) -> {})));
}
}
@Nested
@SuppressWarnings("removal")
class DeprecationForRemovalTests {
private static final TestCompiler TEST_COMPILER = TestCompiler.forSystem()
.withCompilerOptions("-Xlint:all", "-Xlint:-rawtypes", "-Werror");
@Test
@Disabled("Need to move to a separate method so that the warning can be suppressed")
void generateWhenTargetClassIsDeprecatedForRemoval() {
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedForRemovalBean.class));
}
@Test
void generateWhenTargetConstructorIsDeprecatedForRemoval() {
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedForRemovalConstructor.class));
}
@Test
void generateWhenTargetFactoryMethodIsDeprecatedForRemoval() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(String.class)
.setFactoryMethodOnBean("deprecatedString", "config").getBeanDefinition();
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(DeprecatedForRemovalMemberConfiguration.class).getBeanDefinition());
compileAndCheckWarnings(beanDefinition);
}
@Test
void generateWhenTargetFactoryMethodParameterIsDeprecatedForRemoval() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(String.class)
.setFactoryMethodOnBean("deprecatedParameter", "config").getBeanDefinition();
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(DeprecatedForRemovalMemberConfiguration.class).getBeanDefinition());
beanFactory.registerBeanDefinition("parameter", new RootBeanDefinition(DeprecatedForRemovalBean.class));
compileAndCheckWarnings(beanDefinition);
}
private void compileAndCheckWarnings(BeanDefinition beanDefinition) {
assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, beanDefinition,
((instanceSupplier, compiled) -> {})));
}
}
private ReflectionHints getReflectionHints() {
return this.generationContext.getRuntimeHints().reflection();
@@ -438,4 +333,106 @@ class InstanceSupplierCodeGeneratorTests {
(InstanceSupplier<?>) compiled.getInstance(Supplier.class).get(), compiled));
}
@Nested
@SuppressWarnings("deprecation")
class DeprecationTests {
private static final TestCompiler TEST_COMPILER = TestCompiler.forSystem()
.withCompilerOptions("-Xlint:all", "-Xlint:-rawtypes", "-Werror");
@Test
@Disabled("Need to move to a separate method so that the warning can be suppressed")
void generateWhenTargetClassIsDeprecated() {
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedBean.class));
}
@Test
void generateWhenTargetConstructorIsDeprecated() {
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedConstructor.class));
}
@Test
void generateWhenTargetFactoryMethodIsDeprecated() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(String.class)
.setFactoryMethodOnBean("deprecatedString", "config").getBeanDefinition();
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
compileAndCheckWarnings(beanDefinition);
}
@Test
void generateWhenTargetFactoryMethodParameterIsDeprecated() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(String.class)
.setFactoryMethodOnBean("deprecatedParameter", "config").getBeanDefinition();
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
beanFactory.registerBeanDefinition("parameter", new RootBeanDefinition(DeprecatedBean.class));
compileAndCheckWarnings(beanDefinition);
}
@Test
void generateWhenTargetFactoryMethodReturnTypeIsDeprecated() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(DeprecatedBean.class)
.setFactoryMethodOnBean("deprecatedReturnType", "config").getBeanDefinition();
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
compileAndCheckWarnings(beanDefinition);
}
private void compileAndCheckWarnings(BeanDefinition beanDefinition) {
assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, beanDefinition,
((instanceSupplier, compiled) -> {})));
}
}
@Nested
@SuppressWarnings("removal")
class DeprecationForRemovalTests {
private static final TestCompiler TEST_COMPILER = TestCompiler.forSystem()
.withCompilerOptions("-Xlint:all", "-Xlint:-rawtypes", "-Werror");
@Test
@Disabled("Need to move to a separate method so that the warning can be suppressed")
void generateWhenTargetClassIsDeprecatedForRemoval() {
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedForRemovalBean.class));
}
@Test
void generateWhenTargetConstructorIsDeprecatedForRemoval() {
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedForRemovalConstructor.class));
}
@Test
void generateWhenTargetFactoryMethodIsDeprecatedForRemoval() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(String.class)
.setFactoryMethodOnBean("deprecatedString", "config").getBeanDefinition();
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(DeprecatedForRemovalMemberConfiguration.class).getBeanDefinition());
compileAndCheckWarnings(beanDefinition);
}
@Test
void generateWhenTargetFactoryMethodParameterIsDeprecatedForRemoval() {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(String.class)
.setFactoryMethodOnBean("deprecatedParameter", "config").getBeanDefinition();
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
.genericBeanDefinition(DeprecatedForRemovalMemberConfiguration.class).getBeanDefinition());
beanFactory.registerBeanDefinition("parameter", new RootBeanDefinition(DeprecatedForRemovalBean.class));
compileAndCheckWarnings(beanDefinition);
}
private void compileAndCheckWarnings(BeanDefinition beanDefinition) {
assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, beanDefinition,
((instanceSupplier, compiled) -> {})));
}
}
}

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.
@@ -26,6 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
/**
* Tests for {@link RootBeanDefinition}.
@@ -54,7 +55,7 @@ class RootBeanDefinitionTests {
beanDefinition.setResolvedFactoryMethod(method);
beanDefinition.setInstanceSupplier(instanceSupplier);
assertThat(beanDefinition.getResolvedFactoryMethod()).isEqualTo(method);
verify(instanceSupplier).getFactoryMethod();
verifyNoInteractions(instanceSupplier);
}
@Test
@@ -81,15 +82,15 @@ class RootBeanDefinitionTests {
assertThat(beanDefinition.getDestroyMethodNames()).isNull();
}
static class BeanWithCloseMethod {
public void close() {
}
}
static class BeanWithNoDestroyMethod {
static class BeanWithNoDestroyMethod {
}
}

View File

@@ -87,7 +87,7 @@ class InstanceSupplierCodeGeneratorKotlinTests {
Assertions.assertThat(bean).isInstanceOf(String::class.java)
Assertions.assertThat(bean).isEqualTo("Hello")
Assertions.assertThat(compiled.sourceFile).contains(
"getBeanFactory().getBean(KotlinConfiguration.class).stringBean()"
"getBeanFactory().getBean(\"config\", KotlinConfiguration.class).stringBean()"
)
}
Assertions.assertThat<TypeHint?>(getReflectionHints().getTypeHint(KotlinConfiguration::class.java))