Add generics to BeanInstanceSupplier

Update `BeanInstanceSupplier` to support a generic type.

See gh-28748
This commit is contained in:
Phillip Webb
2022-07-21 13:27:24 +01:00
parent 069d6d3280
commit cfb61d2a17
7 changed files with 167 additions and 94 deletions

View File

@@ -158,6 +158,45 @@ class BeanDefinitionMethodGeneratorTests {
});
}
@Test // gh-28748
void generateBeanDefinitionMethodWhenHasInstancePostProcessorAndFactoryMethodGeneratesMethod() {
this.beanFactory.registerBeanDefinition("testBeanConfiguration", new RootBeanDefinition(TestBeanConfiguration.class));
RootBeanDefinition beanDefinition = new RootBeanDefinition(TestBean.class);
beanDefinition.setFactoryBeanName("testBeanConfiguration");
beanDefinition.setFactoryMethodName("testBean");
RegisteredBean registeredBean = registerBean(beanDefinition);
BeanRegistrationAotContribution aotContribution = (generationContext,
beanRegistrationCode) -> {
GeneratedMethod generatedMethod = beanRegistrationCode.getMethods().add("postProcess", method ->
method.addModifiers(Modifier.STATIC)
.addParameter(RegisteredBean.class, "registeredBean")
.addParameter(TestBean.class, "testBean")
.returns(TestBean.class).addCode("return new $T($S);", TestBean.class, "postprocessed"));
beanRegistrationCode.addInstancePostProcessor(MethodReference.ofStatic(
beanRegistrationCode.getClassName(), generatedMethod.getName()));
};
List<BeanRegistrationAotContribution> aotContributions = Collections
.singletonList(aotContribution);
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, aotContributions);
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode);
compile(method, (actual, compiled) -> {
assertThat(compiled.getSourceFile(".*BeanDefinitions")).contains("BeanInstanceSupplier");
assertThat(actual.getBeanClass()).isEqualTo(TestBean.class);
InstanceSupplier<?> supplier = (InstanceSupplier<?>) actual
.getInstanceSupplier();
try {
TestBean instance = (TestBean) supplier.get(registeredBean);
assertThat(instance.getName()).isEqualTo("postprocessed");
}
catch (Exception ex) {
}
SourceFile sourceFile = compiled.getSourceFile(".*BeanDefinitions");
assertThat(sourceFile).contains("instanceSupplier.andThen(");
});
}
@Test
void generateBeanDefinitionMethodWhenHasCodeFragmentsCustomizerGeneratesMethod() {
RegisteredBean registeredBean = registerBean(
@@ -373,7 +412,7 @@ class BeanDefinitionMethodGeneratorTests {
.addCode("return $L;", method.toInvokeCodeBlock()).build());
});
this.generationContext.writeGeneratedContent();
TestCompiler.forSystem().withFiles(this.generatedFiles).compile(compiled ->
TestCompiler.forSystem().withFiles(this.generatedFiles).printFiles(System.out).compile(compiled ->
result.accept((RootBeanDefinition) compiled.getInstance(Supplier.class).get(), compiled));
}

View File

@@ -94,7 +94,7 @@ class BeanInstanceSupplierTests {
@Test
void forConstructorWhenNotFoundThrowsException() {
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<InputStream> resolver = BeanInstanceSupplier
.forConstructor(InputStream.class);
Source source = new Source(SingleArgConstructor.class, resolver);
RegisteredBean registerBean = source.registerBean(this.beanFactory);
@@ -106,7 +106,7 @@ class BeanInstanceSupplierTests {
@Test
void forConstructorReturnsNullFactoryMethod() {
BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(String.class);
BeanInstanceSupplier<Object> resolver = BeanInstanceSupplier.forConstructor(String.class);
assertThat(resolver.getFactoryMethod()).isNull();
}
@@ -146,7 +146,7 @@ class BeanInstanceSupplierTests {
@Test
void forFactoryMethodWhenNotFoundThrowsException() {
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<InputStream> resolver = BeanInstanceSupplier
.forFactoryMethod(SingleArgFactory.class, "single", InputStream.class);
Source source = new Source(String.class, resolver);
RegisteredBean registerBean = source.registerBean(this.beanFactory);
@@ -158,7 +158,7 @@ class BeanInstanceSupplierTests {
@Test
void forFactoryMethodReturnsFactoryMethod() {
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<String> resolver = BeanInstanceSupplier
.forFactoryMethod(SingleArgFactory.class, "single", String.class);
Method factoryMethod = ReflectionUtils.findMethod(SingleArgFactory.class, "single", String.class);
assertThat(factoryMethod).isNotNull();
@@ -167,7 +167,7 @@ class BeanInstanceSupplierTests {
@Test
void withGeneratorWhenBiFunctionIsNullThrowsException() {
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<Object> resolver = BeanInstanceSupplier
.forConstructor();
assertThatIllegalArgumentException()
.isThrownBy(() -> resolver.withGenerator(
@@ -177,7 +177,7 @@ class BeanInstanceSupplierTests {
@Test
void withGeneratorWhenFunctionIsNullThrowsException() {
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<Object> resolver = BeanInstanceSupplier
.forConstructor();
assertThatIllegalArgumentException()
.isThrownBy(() -> resolver.withGenerator(
@@ -187,7 +187,7 @@ class BeanInstanceSupplierTests {
@Test
void withGeneratorWhenSupplierIsNullThrowsException() {
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<Object> resolver = BeanInstanceSupplier
.forConstructor();
assertThatIllegalArgumentException()
.isThrownBy(() -> resolver.withGenerator(
@@ -197,7 +197,7 @@ class BeanInstanceSupplierTests {
@Test
void getWithConstructorDoesNotSetResolvedFactoryMethod() throws Exception {
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<SingleArgConstructor> resolver = BeanInstanceSupplier
.forConstructor(String.class);
this.beanFactory.registerSingleton("one", "1");
Source source = new Source(SingleArgConstructor.class, resolver);
@@ -211,7 +211,7 @@ class BeanInstanceSupplierTests {
void getWithFactoryMethodSetsResolvedFactoryMethod() {
Method factoryMethod = ReflectionUtils.findMethod(SingleArgFactory.class, "single", String.class);
assertThat(factoryMethod).isNotNull();
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<String> resolver = BeanInstanceSupplier
.forFactoryMethod(SingleArgFactory.class, "single", String.class);
RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
assertThat(beanDefinition.getResolvedFactoryMethod()).isNull();
@@ -225,7 +225,7 @@ class BeanInstanceSupplierTests {
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registerBean = registrar.registerBean(this.beanFactory);
List<Object> result = new ArrayList<>();
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<Object> resolver = BeanInstanceSupplier
.forConstructor(String.class)
.withGenerator((registeredBean, args) -> result.add(args));
resolver.get(registerBean);
@@ -238,8 +238,8 @@ class BeanInstanceSupplierTests {
BeanRegistrar registrar = new BeanRegistrar(SingleArgConstructor.class);
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registerBean = registrar.registerBean(this.beanFactory);
BeanInstanceSupplier resolver = BeanInstanceSupplier
.forConstructor(String.class)
BeanInstanceSupplier<String> resolver = BeanInstanceSupplier
.<String>forConstructor(String.class)
.withGenerator(registeredBean -> "1");
assertThat(resolver.get(registerBean)).isInstanceOf(String.class).isEqualTo("1");
}
@@ -249,15 +249,15 @@ class BeanInstanceSupplierTests {
BeanRegistrar registrar = new BeanRegistrar(SingleArgConstructor.class);
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registerBean = registrar.registerBean(this.beanFactory);
BeanInstanceSupplier resolver = BeanInstanceSupplier
.forConstructor(String.class)
BeanInstanceSupplier<String> resolver = BeanInstanceSupplier
.<String>forConstructor(String.class)
.withGenerator(() -> "1");
assertThat(resolver.get(registerBean)).isInstanceOf(String.class).isEqualTo("1");
}
@Test
void getWhenRegisteredBeanIsNullThrowsException() {
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<Object> resolver = BeanInstanceSupplier
.forConstructor(String.class);
assertThatIllegalArgumentException().isThrownBy(() -> resolver.get((RegisteredBean) null))
.withMessage("'registeredBean' must not be null");
@@ -548,7 +548,7 @@ class BeanInstanceSupplierTests {
}
};
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<Object> resolver = BeanInstanceSupplier
.forConstructor(String.class);
Source source = new Source(String.class, resolver);
beanFactory.registerSingleton("one", "1");
@@ -561,7 +561,7 @@ class BeanInstanceSupplierTests {
@Test
void resolveArgumentsRegistersDependantBeans() {
BeanInstanceSupplier resolver = BeanInstanceSupplier
BeanInstanceSupplier<Object> resolver = BeanInstanceSupplier
.forConstructor(String.class);
Source source = new Source(SingleArgConstructor.class, resolver);
this.beanFactory.registerSingleton("one", "1");
@@ -724,7 +724,7 @@ class BeanInstanceSupplierTests {
protected abstract void setup();
protected final void add(Class<?> beanClass,
BeanInstanceSupplier resolver) {
BeanInstanceSupplier<?> resolver) {
this.arguments.add(Arguments.of(new Source(beanClass, resolver)));
}
@@ -762,15 +762,15 @@ class BeanInstanceSupplierTests {
static class Source extends BeanRegistrar {
private final BeanInstanceSupplier resolver;
private final BeanInstanceSupplier<?> resolver;
public Source(Class<?> beanClass,
BeanInstanceSupplier resolver) {
BeanInstanceSupplier<?> resolver) {
super(beanClass);
this.resolver = resolver;
}
BeanInstanceSupplier getResolver() {
BeanInstanceSupplier<?> getResolver() {
return this.resolver;
}

View File

@@ -172,7 +172,7 @@ class InstanceSupplierCodeGeneratorTests {
instanceSupplier);
assertThat(bean).isInstanceOf(TestBeanWithPrivateConstructor.class);
assertThat(compiled.getSourceFile())
.contains("return BeanInstanceSupplier.forConstructor();");
.contains("return BeanInstanceSupplier.<TestBeanWithPrivateConstructor>forConstructor();");
});
assertThat(getReflectionHints().getTypeHint(TestBeanWithPrivateConstructor.class))
.satisfies(hasConstructorWithMode(ExecutableMode.INVOKE));
@@ -211,7 +211,7 @@ class InstanceSupplierCodeGeneratorTests {
assertThat(bean).isInstanceOf(String.class);
assertThat(bean).isEqualTo("Hello");
assertThat(compiled.getSourceFile())
.contains("BeanInstanceSupplier.forFactoryMethod")
.contains("forFactoryMethod")
.doesNotContain("withGenerator");
});
assertThat(getReflectionHints().getTypeHint(SimpleConfiguration.class))
@@ -325,7 +325,7 @@ class InstanceSupplierCodeGeneratorTests {
.addStatement("return $L", generatedCode).build());
});
this.generationContext.writeGeneratedContent();
TestCompiler.forSystem().withFiles(this.generatedFiles).compile(compiled ->
TestCompiler.forSystem().withFiles(this.generatedFiles).printFiles(System.out).compile(compiled ->
result.accept((InstanceSupplier<?>) compiled.getInstance(Supplier.class).get(), compiled));
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2002-2022 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.aot;
import org.springframework.beans.testfixture.beans.TestBean;
/**
* Test {@code @Configuration} style class to create {@link TestBean}.
*
* @author Phillip Webb
*/
public class TestBeanConfiguration {
public TestBean testBean() {
return new TestBean();
}
}