@ -33,6 +33,7 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RegisteredBean ;
import org.springframework.beans.factory.support.RegisteredBean ;
import org.springframework.javapoet.ClassName ;
import org.springframework.javapoet.ClassName ;
import org.springframework.javapoet.CodeBlock ;
import org.springframework.javapoet.CodeBlock ;
import org.springframework.javapoet.CodeBlock.Builder ;
import org.springframework.javapoet.MethodSpec ;
import org.springframework.javapoet.MethodSpec ;
/ * *
/ * *
@ -51,6 +52,9 @@ class BeanRegistrationsAotContribution
private static final String BEAN_FACTORY_PARAMETER_NAME = "beanFactory" ;
private static final String BEAN_FACTORY_PARAMETER_NAME = "beanFactory" ;
private static final ArgumentCodeGenerator argumentCodeGenerator = ArgumentCodeGenerator
. of ( DefaultListableBeanFactory . class , BEAN_FACTORY_PARAMETER_NAME ) ;
private final List < Registration > registrations ;
private final List < Registration > registrations ;
@ -69,8 +73,8 @@ class BeanRegistrationsAotContribution
type . addModifiers ( Modifier . PUBLIC ) ;
type . addModifiers ( Modifier . PUBLIC ) ;
} ) ;
} ) ;
BeanRegistrationsCodeGenerator codeGenerator = new BeanRegistrationsCodeGenerator ( generatedClass ) ;
BeanRegistrationsCodeGenerator codeGenerator = new BeanRegistrationsCodeGenerator ( generatedClass ) ;
GeneratedMethod generatedBeanDefinitionsMethod = codeGenerator . getMethods ( ) . add ( "registerBeanDefinitions" , method - >
GeneratedMethod generatedBeanDefinitionsMethod = new BeanDefinitionsRegistrationGenerator (
generateRegisterBeanDefinitionsMethod ( method , generationContext , codeGenerator ) ) ;
generationContext , codeGenerator , this . registrations ) . generateRegisterBeanDefinitionsMethod ( ) ;
beanFactoryInitializationCode . addInitializer ( generatedBeanDefinitionsMethod . toMethodReference ( ) ) ;
beanFactoryInitializationCode . addInitializer ( generatedBeanDefinitionsMethod . toMethodReference ( ) ) ;
GeneratedMethod generatedAliasesMethod = codeGenerator . getMethods ( ) . add ( "registerAliases" ,
GeneratedMethod generatedAliasesMethod = codeGenerator . getMethods ( ) . add ( "registerAliases" ,
this : : generateRegisterAliasesMethod ) ;
this : : generateRegisterAliasesMethod ) ;
@ -78,33 +82,6 @@ class BeanRegistrationsAotContribution
generateRegisterHints ( generationContext . getRuntimeHints ( ) , this . registrations ) ;
generateRegisterHints ( generationContext . getRuntimeHints ( ) , this . registrations ) ;
}
}
private void generateRegisterBeanDefinitionsMethod ( MethodSpec . Builder method ,
GenerationContext generationContext , BeanRegistrationsCode beanRegistrationsCode ) {
method . addJavadoc ( "Register the bean definitions." ) ;
method . addModifiers ( Modifier . PUBLIC ) ;
method . addParameter ( DefaultListableBeanFactory . class , BEAN_FACTORY_PARAMETER_NAME ) ;
CodeBlock . Builder code = CodeBlock . builder ( ) ;
this . registrations . forEach ( registration - > {
try {
MethodReference beanDefinitionMethod = registration . methodGenerator
. generateBeanDefinitionMethod ( generationContext , beanRegistrationsCode ) ;
CodeBlock methodInvocation = beanDefinitionMethod . toInvokeCodeBlock (
ArgumentCodeGenerator . none ( ) , beanRegistrationsCode . getClassName ( ) ) ;
code . addStatement ( "$L.registerBeanDefinition($S, $L)" ,
BEAN_FACTORY_PARAMETER_NAME , registration . beanName ( ) , methodInvocation ) ;
}
catch ( AotException ex ) {
throw ex ;
}
catch ( Exception ex ) {
throw new AotBeanProcessingException ( registration . registeredBean ,
"failed to generate code for bean definition" , ex ) ;
}
} ) ;
method . addCode ( code . build ( ) ) ;
}
private void generateRegisterAliasesMethod ( MethodSpec . Builder method ) {
private void generateRegisterAliasesMethod ( MethodSpec . Builder method ) {
method . addJavadoc ( "Register the aliases." ) ;
method . addJavadoc ( "Register the aliases." ) ;
method . addModifiers ( Modifier . PUBLIC ) ;
method . addModifiers ( Modifier . PUBLIC ) ;
@ -167,4 +144,89 @@ class BeanRegistrationsAotContribution
}
}
static final class BeanDefinitionsRegistrationGenerator {
private final GenerationContext generationContext ;
private final BeanRegistrationsCodeGenerator codeGenerator ;
private final List < Registration > registrations ;
BeanDefinitionsRegistrationGenerator ( GenerationContext generationContext ,
BeanRegistrationsCodeGenerator codeGenerator , List < Registration > registrations ) {
this . generationContext = generationContext ;
this . codeGenerator = codeGenerator ;
this . registrations = registrations ;
}
GeneratedMethod generateRegisterBeanDefinitionsMethod ( ) {
return this . codeGenerator . getMethods ( ) . add ( "registerBeanDefinitions" , method - > {
method . addJavadoc ( "Register the bean definitions." ) ;
method . addModifiers ( Modifier . PUBLIC ) ;
method . addParameter ( DefaultListableBeanFactory . class , BEAN_FACTORY_PARAMETER_NAME ) ;
if ( this . registrations . size ( ) < = 1000 ) {
generateRegisterBeanDefinitionMethods ( method , this . registrations ) ;
}
else {
Builder code = CodeBlock . builder ( ) ;
code . add ( "// Registration is sliced to avoid exceeding size limit\n" ) ;
int index = 0 ;
int end = 0 ;
while ( end < this . registrations . size ( ) ) {
int start = index * 1000 ;
end = Math . min ( start + 1000 , this . registrations . size ( ) ) ;
GeneratedMethod sliceMethod = generateSliceMethod ( start , end ) ;
code . addStatement ( sliceMethod . toMethodReference ( ) . toInvokeCodeBlock (
argumentCodeGenerator , this . codeGenerator . getClassName ( ) ) ) ;
index + + ;
}
method . addCode ( code . build ( ) ) ;
}
} ) ;
}
private GeneratedMethod generateSliceMethod ( int start , int end ) {
String description = "Register the bean definitions from %s to %s." . formatted ( start , end - 1 ) ;
List < Registration > slice = this . registrations . subList ( start , end ) ;
return this . codeGenerator . getMethods ( ) . add ( "registerBeanDefinitions" , method - > {
method . addJavadoc ( description ) ;
method . addModifiers ( Modifier . PRIVATE ) ;
method . addParameter ( DefaultListableBeanFactory . class , BEAN_FACTORY_PARAMETER_NAME ) ;
generateRegisterBeanDefinitionMethods ( method , slice ) ;
} ) ;
}
private void generateRegisterBeanDefinitionMethods ( MethodSpec . Builder method ,
Iterable < Registration > registrations ) {
CodeBlock . Builder code = CodeBlock . builder ( ) ;
registrations . forEach ( registration - > {
try {
CodeBlock methodInvocation = generateBeanRegistration ( registration ) ;
code . addStatement ( "$L.registerBeanDefinition($S, $L)" ,
BEAN_FACTORY_PARAMETER_NAME , registration . beanName ( ) , methodInvocation ) ;
}
catch ( AotException ex ) {
throw ex ;
}
catch ( Exception ex ) {
throw new AotBeanProcessingException ( registration . registeredBean ,
"failed to generate code for bean definition" , ex ) ;
}
} ) ;
method . addCode ( code . build ( ) ) ;
}
private CodeBlock generateBeanRegistration ( Registration registration ) {
MethodReference beanDefinitionMethod = registration . methodGenerator
. generateBeanDefinitionMethod ( this . generationContext , this . codeGenerator ) ;
return beanDefinitionMethod . toInvokeCodeBlock (
ArgumentCodeGenerator . none ( ) , this . codeGenerator . getClassName ( ) ) ;
}
}
}
}