@ -1,5 +1,5 @@
@@ -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 .
@ -46,6 +46,7 @@ import org.springframework.beans.factory.support.AutowireCandidateResolver;
@@ -46,6 +46,7 @@ import org.springframework.beans.factory.support.AutowireCandidateResolver;
import org.springframework.beans.factory.support.DefaultListableBeanFactory ;
import org.springframework.beans.factory.support.InstanceSupplier ;
import org.springframework.beans.factory.support.RegisteredBean ;
import org.springframework.beans.factory.support.RegisteredBean.InstantiationDescriptor ;
import org.springframework.core.KotlinDetector ;
import org.springframework.core.MethodParameter ;
import org.springframework.core.ResolvableType ;
@ -120,14 +121,29 @@ public class InstanceSupplierCodeGenerator {
@@ -120,14 +121,29 @@ public class InstanceSupplierCodeGenerator {
* @param registeredBean the bean to handle
* @param constructorOrFactoryMethod the executable to use to create the bean
* @return the generated code
* @deprecated in favor of { @link # generateCode ( RegisteredBean , InstantiationDescriptor ) }
* /
@Deprecated ( since = "6.1.7" )
public CodeBlock generateCode ( RegisteredBean registeredBean , Executable constructorOrFactoryMethod ) {
return generateCode ( registeredBean , new InstantiationDescriptor (
constructorOrFactoryMethod , constructorOrFactoryMethod . getDeclaringClass ( ) ) ) ;
}
/ * *
* Generate the instance supplier code .
* @param registeredBean the bean to handle
* @param instantiationDescriptor the executable to use to create the bean
* @return the generated code
* @since 6 . 1 . 7
* /
public CodeBlock generateCode ( RegisteredBean registeredBean , InstantiationDescriptor instantiationDescriptor ) {
Executable constructorOrFactoryMethod = instantiationDescriptor . executable ( ) ;
registerRuntimeHintsIfNecessary ( registeredBean , constructorOrFactoryMethod ) ;
if ( constructorOrFactoryMethod instanceof Constructor < ? > constructor ) {
return generateCodeForConstructor ( registeredBean , constructor ) ;
}
if ( constructorOrFactoryMethod instanceof Method method ) {
return generateCodeForFactoryMethod ( registeredBean , method ) ;
return generateCodeForFactoryMethod ( registeredBean , method , instantiationDescriptor . targetClass ( ) ) ;
}
throw new IllegalStateException (
"No suitable executor found for " + registeredBean . getBeanName ( ) ) ;
@ -253,21 +269,21 @@ public class InstanceSupplierCodeGenerator {
@@ -253,21 +269,21 @@ public class InstanceSupplierCodeGenerator {
declaringClass . getSimpleName ( ) , args ) ;
}
private CodeBlock generateCodeForFactoryMethod ( RegisteredBean registeredBean , Method factoryMethod ) {
private CodeBlock generateCodeForFactoryMethod ( RegisteredBean registeredBean , Method factoryMethod , Class < ? > targetClass ) {
String beanName = registeredBean . getBeanName ( ) ;
Class < ? > declaringClass = ClassUtils . getUserClass ( factoryMethod . getDeclaringClass ( ) ) ;
Class < ? > targetClassToUse = ClassUtils . getUserClass ( targetClass ) ;
boolean dependsOnBean = ! Modifier . isStatic ( factoryMethod . getModifiers ( ) ) ;
Visibility accessVisibility = getAccessVisibility ( registeredBean , factoryMethod ) ;
if ( accessVisibility ! = Visibility . PRIVATE ) {
return generateCodeForAccessibleFactoryMethod (
beanName , factoryMethod , declaringClass , dependsOnBean ) ;
beanName , factoryMethod , targetClassToUse , dependsOnBean ) ;
}
return generateCodeForInaccessibleFactoryMethod ( beanName , factoryMethod , declaringClass ) ;
return generateCodeForInaccessibleFactoryMethod ( beanName , factoryMethod , targetClassToUse ) ;
}
private CodeBlock generateCodeForAccessibleFactoryMethod ( String beanName ,
Method factoryMethod , Class < ? > declaring Class, boolean dependsOnBean ) {
Method factoryMethod , Class < ? > target Class, boolean dependsOnBean ) {
this . generationContext . getRuntimeHints ( ) . reflection ( ) . registerMethod (
factoryMethod , ExecutableMode . INTROSPECT ) ;
@ -276,20 +292,20 @@ public class InstanceSupplierCodeGenerator {
@@ -276,20 +292,20 @@ public class InstanceSupplierCodeGenerator {
Class < ? > suppliedType = ClassUtils . resolvePrimitiveIfNecessary ( factoryMethod . getReturnType ( ) ) ;
CodeBlock . Builder code = CodeBlock . builder ( ) ;
code . add ( "$T.<$T>forFactoryMethod($T.class, $S)" , BeanInstanceSupplier . class ,
suppliedType , declaring Class, factoryMethod . getName ( ) ) ;
suppliedType , target Class, factoryMethod . getName ( ) ) ;
code . add ( ".withGenerator(($L) -> $T.$L())" , REGISTERED_BEAN_PARAMETER_NAME ,
declaring Class, factoryMethod . getName ( ) ) ;
target Class, factoryMethod . getName ( ) ) ;
return code . build ( ) ;
}
GeneratedMethod getInstanceMethod = generateGetInstanceSupplierMethod ( method - >
buildGetInstanceMethodForFactoryMethod ( method , beanName , factoryMethod ,
declaring Class, dependsOnBean , PRIVATE_STATIC ) ) ;
target Class, dependsOnBean , PRIVATE_STATIC ) ) ;
return generateReturnStatement ( getInstanceMethod ) ;
}
private CodeBlock generateCodeForInaccessibleFactoryMethod (
String beanName , Method factoryMethod , Class < ? > declaring Class) {
String beanName , Method factoryMethod , Class < ? > target Class) {
this . generationContext . getRuntimeHints ( ) . reflection ( ) . registerMethod ( factoryMethod , ExecutableMode . INVOKE ) ;
GeneratedMethod getInstanceMethod = generateGetInstanceSupplierMethod ( method - > {
@ -298,19 +314,19 @@ public class InstanceSupplierCodeGenerator {
@@ -298,19 +314,19 @@ public class InstanceSupplierCodeGenerator {
method . addModifiers ( PRIVATE_STATIC ) ;
method . returns ( ParameterizedTypeName . get ( BeanInstanceSupplier . class , suppliedType ) ) ;
method . addStatement ( generateInstanceSupplierForFactoryMethod (
factoryMethod , suppliedType , declaring Class, factoryMethod . getName ( ) ) ) ;
factoryMethod , suppliedType , target Class, factoryMethod . getName ( ) ) ) ;
} ) ;
return generateReturnStatement ( getInstanceMethod ) ;
}
private void buildGetInstanceMethodForFactoryMethod ( MethodSpec . Builder method ,
String beanName , Method factoryMethod , Class < ? > declaring Class,
String beanName , Method factoryMethod , Class < ? > target Class,
boolean dependsOnBean , javax . lang . model . element . Modifier . . . modifiers ) {
String factoryMethodName = factoryMethod . getName ( ) ;
Class < ? > suppliedType = ClassUtils . resolvePrimitiveIfNecessary ( factoryMethod . getReturnType ( ) ) ;
CodeWarnings codeWarnings = new CodeWarnings ( ) ;
codeWarnings . detectDeprecation ( declaring Class, factoryMethod , suppliedType )
codeWarnings . detectDeprecation ( target Class, factoryMethod , suppliedType )
. detectDeprecation ( Arrays . stream ( factoryMethod . getParameters ( ) ) . map ( Parameter : : getType ) ) ;
method . addJavadoc ( "Get the bean instance supplier for '$L'." , beanName ) ;
@ -320,41 +336,41 @@ public class InstanceSupplierCodeGenerator {
@@ -320,41 +336,41 @@ public class InstanceSupplierCodeGenerator {
CodeBlock . Builder code = CodeBlock . builder ( ) ;
code . add ( generateInstanceSupplierForFactoryMethod (
factoryMethod , suppliedType , declaring Class, factoryMethodName ) ) ;
factoryMethod , suppliedType , target Class, factoryMethodName ) ) ;
boolean hasArguments = factoryMethod . getParameterCount ( ) > 0 ;
CodeBlock arguments = hasArguments ?
new AutowiredArgumentsCodeGenerator ( declaring Class, factoryMethod )
new AutowiredArgumentsCodeGenerator ( target Class, factoryMethod )
. generateCode ( factoryMethod . getParameterTypes ( ) )
: NO_ARGS ;
CodeBlock newInstance = generateNewInstanceCodeForMethod (
dependsOnBean , declaring Class, factoryMethodName , arguments ) ;
dependsOnBean , target Class, factoryMethodName , arguments ) ;
code . add ( generateWithGeneratorCode ( hasArguments , newInstance ) ) ;
method . addStatement ( code . build ( ) ) ;
}
private CodeBlock generateInstanceSupplierForFactoryMethod ( Method factoryMethod ,
Class < ? > suppliedType , Class < ? > declaring Class, String factoryMethodName ) {
Class < ? > suppliedType , Class < ? > target Class, String factoryMethodName ) {
if ( factoryMethod . getParameterCount ( ) = = 0 ) {
return CodeBlock . of ( "return $T.<$T>forFactoryMethod($T.class, $S)" ,
BeanInstanceSupplier . class , suppliedType , declaring Class, factoryMethodName ) ;
BeanInstanceSupplier . class , suppliedType , target Class, factoryMethodName ) ;
}
CodeBlock parameterTypes = generateParameterTypesCode ( factoryMethod . getParameterTypes ( ) , 0 ) ;
return CodeBlock . of ( "return $T.<$T>forFactoryMethod($T.class, $S, $L)" ,
BeanInstanceSupplier . class , suppliedType , declaring Class, factoryMethodName , parameterTypes ) ;
BeanInstanceSupplier . class , suppliedType , target Class, factoryMethodName , parameterTypes ) ;
}
private CodeBlock generateNewInstanceCodeForMethod ( boolean dependsOnBean ,
Class < ? > declaring Class, String factoryMethodName , CodeBlock args ) {
Class < ? > target Class, String factoryMethodName , CodeBlock args ) {
if ( ! dependsOnBean ) {
return CodeBlock . of ( "$T.$L($L)" , declaring Class, factoryMethodName , args ) ;
return CodeBlock . of ( "$T.$L($L)" , target Class, factoryMethodName , args ) ;
}
return CodeBlock . of ( "$L.getBeanFactory().getBean($T.class).$L($L)" ,
REGISTERED_BEAN_PARAMETER_NAME , declaring Class, factoryMethodName , args ) ;
REGISTERED_BEAN_PARAMETER_NAME , target Class, factoryMethodName , args ) ;
}
private CodeBlock generateReturnStatement ( GeneratedMethod generatedMethod ) {