@ -16,10 +16,14 @@
@@ -16,10 +16,14 @@
package org.springframework.beans.factory.aot ;
import java.lang.reflect.Constructor ;
import java.lang.reflect.Executable ;
import java.lang.reflect.Method ;
import java.util.function.UnaryOperator ;
import org.junit.jupiter.api.Test ;
import org.springframework.aot.generate.GenerationContext ;
import org.springframework.aot.test.generate.TestGenerationContext ;
import org.springframework.beans.factory.FactoryBean ;
import org.springframework.beans.factory.annotation.InjectAnnotationBeanPostProcessorTests.StringFactoryBean ;
@ -28,6 +32,7 @@ import org.springframework.beans.factory.support.RegisteredBean;
@@ -28,6 +32,7 @@ import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition ;
import org.springframework.beans.testfixture.beans.factory.DummyFactory ;
import org.springframework.beans.testfixture.beans.factory.aot.GenericFactoryBean ;
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanRegistrationCode ;
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanRegistrationsCode ;
import org.springframework.beans.testfixture.beans.factory.aot.NumberFactoryBean ;
import org.springframework.beans.testfixture.beans.factory.aot.SimpleBean ;
@ -35,9 +40,14 @@ import org.springframework.beans.testfixture.beans.factory.aot.SimpleBeanConfigu
@@ -35,9 +40,14 @@ import org.springframework.beans.testfixture.beans.factory.aot.SimpleBeanConfigu
import org.springframework.beans.testfixture.beans.factory.aot.SimpleBeanFactoryBean ;
import org.springframework.core.ResolvableType ;
import org.springframework.javapoet.ClassName ;
import org.springframework.javapoet.CodeBlock ;
import org.springframework.lang.Nullable ;
import org.springframework.util.ReflectionUtils ;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.mockito.Mockito.never ;
import static org.mockito.Mockito.spy ;
import static org.mockito.Mockito.verify ;
/ * *
* Tests for { @link DefaultBeanRegistrationCodeFragments } .
@ -48,136 +58,202 @@ class DefaultBeanRegistrationCodeFragmentsTests {
@@ -48,136 +58,202 @@ class DefaultBeanRegistrationCodeFragmentsTests {
private final BeanRegistrationsCode beanRegistrationsCode = new MockBeanRegistrationsCode ( new TestGenerationContext ( ) ) ;
private final GenerationContext generationContext = new TestGenerationContext ( ) ;
private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory ( ) ;
@Test
void getTargetOnConstructor ( ) {
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ,
SimpleBean . class . getDeclaredConstructors ( ) [ 0 ] ) , SimpleBean . class ) ;
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ,
SimpleBean . class . getDeclaredConstructors ( ) [ 0 ] ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ) , SimpleBean . class ) ;
}
@Test
void getTargetOnConstructorToPublicFactoryBean ( ) {
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ,
SimpleBeanFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) , SimpleBean . class ) ;
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ,
SimpleBeanFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ) , SimpleBean . class ) ;
}
@Test
void getTargetOnConstructorToPublicGenericFactoryBeanExtractTargetFromFactoryBeanType ( ) {
RegisteredBean registeredBean = registerTestBean ( ResolvableType
. forClassWithGenerics ( GenericFactoryBean . class , SimpleBean . class ) ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ,
GenericFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) , SimpleBean . class ) ;
ResolvableType beanType = ResolvableType . forClassWithGenerics (
GenericFactoryBean . class , SimpleBean . class ) ;
RegisteredBean registeredBean = registerTestBean ( beanType ,
GenericFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ) , SimpleBean . class ) ;
}
@Test
void getTargetOnConstructorToPublicGenericFactoryBeanWithBoundExtractTargetFromFactoryBeanType ( ) {
RegisteredBean registeredBean = registerTestBean ( ResolvableType
. forClassWithGenerics ( NumberFactoryBean . class , Integer . class ) ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ,
NumberFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) , Integer . class ) ;
ResolvableType beanType = ResolvableType . forClassWithGenerics (
NumberFactoryBean . class , Integer . class ) ;
RegisteredBean registeredBean = registerTestBean ( beanType ,
NumberFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ) , Integer . class ) ;
}
@Test
void getTargetOnConstructorToPublicGenericFactoryBeanUseBeanTypeAsFallback ( ) {
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ,
GenericFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) , SimpleBean . class ) ;
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ,
GenericFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ) , SimpleBean . class ) ;
}
@Test
void getTargetOnConstructorToProtectedFactoryBean ( ) {
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ,
PrivilegedTestBeanFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) ,
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ,
PrivilegedTestBeanFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ) ,
PrivilegedTestBeanFactoryBean . class ) ;
}
@Test
void getTargetOnMethod ( ) {
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ) ;
Method method = ReflectionUtils . findMethod ( SimpleBeanConfiguration . class , "simpleBean" ) ;
assertThat ( method ) . isNotNull ( ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean , method ) ,
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class , method ) ;
assertTarget ( createInstance ( registeredBean ) . getTarget ( registeredBean ) ,
SimpleBeanConfiguration . class ) ;
}
@Test
void getTargetOnMethodWithInnerBeanInJavaPackage ( ) {
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ) ;
RegisteredBean innerBean = RegisteredBean . ofInnerBean ( registeredBean , "innerTestBean" ,
new RootBeanDefinition ( String . class ) ) ;
Method method = ReflectionUtils . findMethod ( getClass ( ) , "createString" ) ;
assertThat ( method ) . isNotNull ( ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean , method ) , getClass ( ) ) ;
RegisteredBean innerBean = RegisteredBean . ofInnerBean ( registeredBean , "innerTestBean" ,
applyConstructorOrFactoryMethod ( new RootBeanDefinition ( String . class ) , method ) ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean ) , getClass ( ) ) ;
}
@Test
void getTargetOnConstructorWithInnerBeanInJavaPackage ( ) {
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ) ;
RegisteredBean innerBean = RegisteredBean . ofInnerBean ( registeredBean , "innerTestBean" , new RootBeanDefinition ( String . class ) ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean ,
String . class . getDeclaredConstructors ( ) [ 0 ] ) , SimpleBean . class ) ;
RootBeanDefinition innerBeanDefinition = applyConstructorOrFactoryMethod (
new RootBeanDefinition ( String . class ) , String . class . getDeclaredConstructors ( ) [ 0 ] ) ;
RegisteredBean innerBean = RegisteredBean . ofInnerBean ( registeredBean , "innerTestBean" ,
innerBeanDefinition ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean ) , SimpleBean . class ) ;
}
@Test
void getTargetOnConstructorWithInnerBeanOnTypeInJavaPackage ( ) {
RegisteredBean registeredBean = registerTestBean ( SimpleBean . class ) ;
RootBeanDefinition innerBeanDefinition = applyConstructorOrFactoryMethod (
new RootBeanDefinition ( StringFactoryBean . class ) ,
StringFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) ;
RegisteredBean innerBean = RegisteredBean . ofInnerBean ( registeredBean , "innerTestBean" ,
new RootBeanDefinition ( StringFactoryBean . class ) ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean ,
StringFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) , SimpleBean . class ) ;
innerBeanDefinition ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean ) , SimpleBean . class ) ;
}
@Test
void getTargetOnMethodWithInnerBeanInRegularPackage ( ) {
RegisteredBean registeredBean = registerTestBean ( DummyFactory . class ) ;
RegisteredBean innerBean = RegisteredBean . ofInnerBean ( registeredBean , "innerTestBean" ,
new RootBeanDefinition ( SimpleBean . class ) ) ;
Method method = ReflectionUtils . findMethod ( SimpleBeanConfiguration . class , "simpleBean" ) ;
assertThat ( method ) . isNotNull ( ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean , method ) ,
RegisteredBean innerBean = RegisteredBean . ofInnerBean ( registeredBean , "innerTestBean" ,
applyConstructorOrFactoryMethod ( new RootBeanDefinition ( SimpleBean . class ) , method ) ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean ) ,
SimpleBeanConfiguration . class ) ;
}
@Test
void getTargetOnConstructorWithInnerBeanInRegularPackage ( ) {
RegisteredBean registeredBean = registerTestBean ( DummyFactory . class ) ;
RootBeanDefinition innerBeanDefinition = applyConstructorOrFactoryMethod (
new RootBeanDefinition ( SimpleBean . class ) , SimpleBean . class . getDeclaredConstructors ( ) [ 0 ] ) ;
RegisteredBean innerBean = RegisteredBean . ofInnerBean ( registeredBean , "innerTestBean" ,
new RootBeanDefinition ( SimpleBean . class ) ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean ,
SimpleBean . class . getDeclaredConstructors ( ) [ 0 ] ) , SimpleBean . class ) ;
innerBeanDefinition ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean ) , SimpleBean . class ) ;
}
@Test
void getTargetOnConstructorWithInnerBeanOnFactoryBeanOnTypeInRegularPackage ( ) {
RegisteredBean registeredBean = registerTestBean ( DummyFactory . class ) ;
RootBeanDefinition innerBeanDefinition = applyConstructorOrFactoryMethod (
new RootBeanDefinition ( SimpleBean . class ) ,
SimpleBeanFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) ;
RegisteredBean innerBean = RegisteredBean . ofInnerBean ( registeredBean , "innerTestBean" ,
new RootBeanDefinition ( SimpleBean . class ) ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean ,
SimpleBeanFactoryBean . class . getDeclaredConstructors ( ) [ 0 ] ) , SimpleBean . class ) ;
innerBeanDefinition ) ;
assertTarget ( createInstance ( innerBean ) . getTarget ( innerBean ) , SimpleBean . class ) ;
}
@Test
void customizedGetTargetDoesNotResolveConstructorOrFactoryMethod ( ) {
RegisteredBean registeredBean = spy ( registerTestBean ( SimpleBean . class ) ) ;
BeanRegistrationCodeFragments customCodeFragments = createCustomCodeFragments ( registeredBean , codeFragments - > new BeanRegistrationCodeFragmentsDecorator ( codeFragments ) {
@Override
public ClassName getTarget ( RegisteredBean registeredBean ) {
return ClassName . get ( String . class ) ;
}
} ) ;
assertTarget ( customCodeFragments . getTarget ( registeredBean ) , String . class ) ;
verify ( registeredBean , never ( ) ) . resolveConstructorOrFactoryMethod ( ) ;
}
@Test
void customizedGenerateInstanceSupplierCodeDoesNotResolveConstructorOrFactoryMethod ( ) {
RegisteredBean registeredBean = spy ( registerTestBean ( SimpleBean . class ) ) ;
BeanRegistrationCodeFragments customCodeFragments = createCustomCodeFragments ( registeredBean , codeFragments - > new BeanRegistrationCodeFragmentsDecorator ( codeFragments ) {
@Override
public CodeBlock generateInstanceSupplierCode ( GenerationContext generationContext ,
BeanRegistrationCode beanRegistrationCode , boolean allowDirectSupplierShortcut ) {
return CodeBlock . of ( "// Hello" ) ;
}
} ) ;
assertThat ( customCodeFragments . generateInstanceSupplierCode ( this . generationContext ,
new MockBeanRegistrationCode ( this . generationContext ) , false ) ) . hasToString ( "// Hello" ) ;
verify ( registeredBean , never ( ) ) . resolveConstructorOrFactoryMethod ( ) ;
}
private BeanRegistrationCodeFragments createCustomCodeFragments ( RegisteredBean registeredBean , UnaryOperator < BeanRegistrationCodeFragments > customFragments ) {
BeanRegistrationAotContribution aotContribution = BeanRegistrationAotContribution .
withCustomCodeFragments ( customFragments ) ;
BeanRegistrationCodeFragments defaultCodeFragments = createInstance ( registeredBean ) ;
return aotContribution . customizeBeanRegistrationCodeFragments (
this . generationContext , defaultCodeFragments ) ;
}
private void assertTarget ( ClassName target , Class < ? > expected ) {
assertThat ( target ) . isEqualTo ( ClassName . get ( expected ) ) ;
}
private RegisteredBean registerTestBean ( Class < ? > beanType ) {
this . beanFactory . registerBeanDefinition ( "testBean" ,
new RootBeanDefinition ( beanType ) ) ;
return registerTestBean ( beanType , null ) ;
}
private RegisteredBean registerTestBean ( Class < ? > beanType ,
@Nullable Executable constructorOrFactoryMethod ) {
this . beanFactory . registerBeanDefinition ( "testBean" , applyConstructorOrFactoryMethod (
new RootBeanDefinition ( beanType ) , constructorOrFactoryMethod ) ) ;
return RegisteredBean . of ( this . beanFactory , "testBean" ) ;
}
private RegisteredBean registerTestBean ( ResolvableType beanType ) {
private RegisteredBean registerTestBean ( ResolvableType beanType ,
@Nullable Executable constructorOrFactoryMethod ) {
RootBeanDefinition beanDefinition = new RootBeanDefinition ( ) ;
beanDefinition . setTargetType ( beanType ) ;
this . beanFactory . registerBeanDefinition ( "testBean" , beanDefinition ) ;
this . beanFactory . registerBeanDefinition ( "testBean" ,
applyConstructorOrFactoryMethod ( beanDefinition , constructorOrFactoryMethod ) ) ;
return RegisteredBean . of ( this . beanFactory , "testBean" ) ;
}
private RootBeanDefinition applyConstructorOrFactoryMethod ( RootBeanDefinition beanDefinition ,
@Nullable Executable constructorOrFactoryMethod ) {
if ( constructorOrFactoryMethod instanceof Method method ) {
beanDefinition . setResolvedFactoryMethod ( method ) ;
}
else if ( constructorOrFactoryMethod instanceof Constructor < ? > constructor ) {
beanDefinition . setAttribute ( RootBeanDefinition . PREFERRED_CONSTRUCTORS_ATTRIBUTE , constructor ) ;
}
return beanDefinition ;
}
private BeanRegistrationCodeFragments createInstance ( RegisteredBean registeredBean ) {
return new DefaultBeanRegistrationCodeFragments ( this . beanRegistrationsCode , registeredBean ,
new BeanDefinitionMethodGeneratorFactory ( this . beanFactory ) ) ;