71
71
import org .springframework .beans .factory .config .SmartInstantiationAwareBeanPostProcessor ;
72
72
import org .springframework .beans .factory .config .TypedStringValue ;
73
73
import org .springframework .core .DefaultParameterNameDiscoverer ;
74
- import org .springframework .core .GenericTypeResolver ;
75
74
import org .springframework .core .MethodParameter ;
76
75
import org .springframework .core .NamedThreadLocal ;
77
76
import org .springframework .core .ParameterNameDiscoverer ;
82
81
import org .springframework .util .ClassUtils ;
83
82
import org .springframework .util .ObjectUtils ;
84
83
import org .springframework .util .ReflectionUtils ;
84
+ import org .springframework .util .ReflectionUtils .MethodCallback ;
85
85
import org .springframework .util .StringUtils ;
86
86
87
87
/**
@@ -815,87 +815,96 @@ protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition m
815
815
* if present to determine the object type. If not present, i.e. the FactoryBean is
816
816
* declared as a raw type, checks the FactoryBean's {@code getObjectType} method
817
817
* on a plain instance of the FactoryBean, without bean properties applied yet.
818
- * If this doesn't return a type yet, a full creation of the FactoryBean is
819
- * used as fallback (through delegation to the superclass's implementation).
818
+ * If this doesn't return a type yet, and {@code allowInit} is {@code true} a
819
+ * full creation of the FactoryBean is used as fallback (through delegation to the
820
+ * superclass's implementation).
820
821
* <p>The shortcut check for a FactoryBean is only applied in case of a singleton
821
822
* FactoryBean. If the FactoryBean instance itself is not kept as singleton,
822
823
* it will be fully created to check the type of its exposed object.
823
824
*/
824
825
@ Override
825
- @ Nullable
826
- protected Class <?> getTypeForFactoryBean (String beanName , RootBeanDefinition mbd ) {
826
+ protected ResolvableType getTypeForFactoryBean (String beanName ,
827
+ RootBeanDefinition mbd , boolean allowInit ) {
828
+
829
+ ResolvableType result = ResolvableType .NONE ;
830
+
831
+ ResolvableType beanType = mbd .hasBeanClass () ?
832
+ ResolvableType .forClass (mbd .getBeanClass ()) :
833
+ ResolvableType .NONE ;
834
+
835
+ // For instance supplied beans try the target type and bean class
827
836
if (mbd .getInstanceSupplier () != null ) {
828
- ResolvableType targetType = mbd .targetType ;
829
- if (targetType != null ) {
830
- Class <?> result = targetType .as (FactoryBean .class ).getGeneric ().resolve ();
831
- if (result != null ) {
832
- return result ;
833
- }
837
+ result = getFactoryBeanGeneric (mbd .targetType );
838
+ if (result .resolve () != null ) {
839
+ return result ;
834
840
}
835
- if (mbd .hasBeanClass ()) {
836
- Class <?> result = GenericTypeResolver .resolveTypeArgument (mbd .getBeanClass (), FactoryBean .class );
837
- if (result != null ) {
838
- return result ;
839
- }
841
+ result = getFactoryBeanGeneric (beanType );
842
+ if (result .resolve () != null ) {
843
+ return result ;
840
844
}
841
845
}
842
846
847
+ // Consider factory methods
843
848
String factoryBeanName = mbd .getFactoryBeanName ();
844
849
String factoryMethodName = mbd .getFactoryMethodName ();
845
850
851
+ // Scan the factory bean methods
846
852
if (factoryBeanName != null ) {
847
853
if (factoryMethodName != null ) {
848
- // Try to obtain the FactoryBean's object type from its factory method declaration
849
- // without instantiating the containing bean at all.
850
- BeanDefinition fbDef = getBeanDefinition (factoryBeanName );
851
- if (fbDef instanceof AbstractBeanDefinition ) {
852
- AbstractBeanDefinition afbDef = (AbstractBeanDefinition ) fbDef ;
853
- if (afbDef .hasBeanClass ()) {
854
- Class <?> result = getTypeForFactoryBeanFromMethod (afbDef .getBeanClass (), factoryMethodName );
855
- if (result != null ) {
856
- return result ;
857
- }
854
+ // Try to obtain the FactoryBean's object type from its factory method
855
+ // declaration without instantiating the containing bean at all.
856
+ BeanDefinition factoryBeanDefinition = getBeanDefinition (factoryBeanName );
857
+ if (factoryBeanDefinition instanceof AbstractBeanDefinition &&
858
+ ((AbstractBeanDefinition ) factoryBeanDefinition ).hasBeanClass ()) {
859
+ Class <?> factoryBeanClass = ((AbstractBeanDefinition ) factoryBeanDefinition ).getBeanClass ();
860
+ result = getTypeForFactoryBeanFromMethod (factoryBeanClass , factoryMethodName );
861
+ if (result .resolve () != null ) {
862
+ return result ;
858
863
}
859
864
}
860
865
}
861
866
// If not resolvable above and the referenced factory bean doesn't exist yet,
862
867
// exit here - we don't want to force the creation of another bean just to
863
868
// obtain a FactoryBean's object type...
864
869
if (!isBeanEligibleForMetadataCaching (factoryBeanName )) {
865
- return null ;
870
+ return ResolvableType . NONE ;
866
871
}
867
872
}
868
873
869
- // Let's obtain a shortcut instance for an early getObjectType() call...
870
- FactoryBean <?> fb = (mbd .isSingleton () ?
871
- getSingletonFactoryBeanForTypeCheck (beanName , mbd ) :
872
- getNonSingletonFactoryBeanForTypeCheck (beanName , mbd ));
873
-
874
- if (fb != null ) {
875
- // Try to obtain the FactoryBean's object type from this early stage of the instance.
876
- Class <?> result = getTypeForFactoryBean (fb );
877
- if (result != null ) {
878
- return result ;
879
- }
880
- else {
874
+ // If we're allowed, we can create the factory bean and call getObjectType() early
875
+ if (allowInit ) {
876
+ FactoryBean <?> factoryBean = (mbd .isSingleton () ?
877
+ getSingletonFactoryBeanForTypeCheck (beanName , mbd ) :
878
+ getNonSingletonFactoryBeanForTypeCheck (beanName , mbd ));
879
+ if (factoryBean != null ) {
880
+ // Try to obtain the FactoryBean's object type from this early stage of the instance.
881
+ Class <?> type = getTypeForFactoryBean (factoryBean );
882
+ if (type != null ) {
883
+ return ResolvableType .forClass (type );
884
+ }
881
885
// No type found for shortcut FactoryBean instance:
882
886
// fall back to full creation of the FactoryBean instance.
883
- return super .getTypeForFactoryBean (beanName , mbd );
887
+ return super .getTypeForFactoryBean (beanName , mbd , allowInit );
884
888
}
885
889
}
886
890
887
- if (factoryBeanName == null && mbd .hasBeanClass ()) {
891
+ if (factoryBeanName == null && mbd .hasBeanClass () && factoryMethodName != null ) {
888
892
// No early bean instantiation possible: determine FactoryBean's type from
889
893
// static factory method signature or from class inheritance hierarchy...
890
- if (factoryMethodName != null ) {
891
- return getTypeForFactoryBeanFromMethod (mbd .getBeanClass (), factoryMethodName );
892
- }
893
- else {
894
- return GenericTypeResolver .resolveTypeArgument (mbd .getBeanClass (), FactoryBean .class );
895
- }
894
+ return getTypeForFactoryBeanFromMethod (mbd .getBeanClass (), factoryMethodName );
895
+ }
896
+ result = getFactoryBeanGeneric (beanType );
897
+ if (result .resolve () != null ) {
898
+ return result ;
896
899
}
900
+ return ResolvableType .NONE ;
901
+ }
897
902
898
- return null ;
903
+ private ResolvableType getFactoryBeanGeneric (@ Nullable ResolvableType type ) {
904
+ if (type == null ) {
905
+ return ResolvableType .NONE ;
906
+ }
907
+ return type .as (FactoryBean .class ).getGeneric ();
899
908
}
900
909
901
910
/**
@@ -905,36 +914,30 @@ protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd
905
914
* @param factoryMethodName the name of the factory method
906
915
* @return the common {@code FactoryBean} object type, or {@code null} if none
907
916
*/
908
- @ Nullable
909
- private Class <?> getTypeForFactoryBeanFromMethod (Class <?> beanClass , final String factoryMethodName ) {
910
-
911
- /**
912
- * Holder used to keep a reference to a {@code Class} value.
913
- */
914
- class Holder {
915
-
916
- @ Nullable
917
- Class <?> value = null ;
918
- }
919
-
920
- final Holder objectType = new Holder ();
921
-
917
+ private ResolvableType getTypeForFactoryBeanFromMethod (Class <?> beanClass , String factoryMethodName ) {
922
918
// CGLIB subclass methods hide generic parameters; look at the original user class.
923
- Class <?> fbClass = ClassUtils .getUserClass (beanClass );
924
-
925
- // Find the given factory method, taking into account that in the case of
926
- // @Bean methods, there may be parameters present.
927
- ReflectionUtils .doWithMethods (fbClass , method -> {
928
- if (method .getName ().equals (factoryMethodName ) &&
929
- FactoryBean .class .isAssignableFrom (method .getReturnType ())) {
930
- Class <?> currentType = GenericTypeResolver .resolveReturnTypeArgument (method , FactoryBean .class );
931
- if (currentType != null ) {
932
- objectType .value = ClassUtils .determineCommonAncestor (currentType , objectType .value );
933
- }
934
- }
935
- }, ReflectionUtils .USER_DECLARED_METHODS );
919
+ Class <?> factoryBeanClass = ClassUtils .getUserClass (beanClass );
920
+ FactoryBeanMethodTypeFinder finder = new FactoryBeanMethodTypeFinder (factoryMethodName );
921
+ ReflectionUtils .doWithMethods (factoryBeanClass , finder , ReflectionUtils .USER_DECLARED_METHODS );
922
+ return finder .getResult ();
923
+ }
936
924
937
- return (objectType .value != null && Object .class != objectType .value ? objectType .value : null );
925
+ /**
926
+ * This implementation attempts to query the FactoryBean's generic parameter metadata
927
+ * if present to determine the object type. If not present, i.e. the FactoryBean is
928
+ * declared as a raw type, checks the FactoryBean's {@code getObjectType} method
929
+ * on a plain instance of the FactoryBean, without bean properties applied yet.
930
+ * If this doesn't return a type yet, a full creation of the FactoryBean is
931
+ * used as fallback (through delegation to the superclass's implementation).
932
+ * <p>The shortcut check for a FactoryBean is only applied in case of a singleton
933
+ * FactoryBean. If the FactoryBean instance itself is not kept as singleton,
934
+ * it will be fully created to check the type of its exposed object.
935
+ */
936
+ @ Override
937
+ @ Deprecated
938
+ @ Nullable
939
+ protected Class <?> getTypeForFactoryBean (String beanName , RootBeanDefinition mbd ) {
940
+ return getTypeForFactoryBean (beanName , mbd , true ).resolve ();
938
941
}
939
942
940
943
/**
@@ -1983,4 +1986,51 @@ public String getDependencyName() {
1983
1986
}
1984
1987
}
1985
1988
1989
+ /**
1990
+ * {@link MethodCallback} used to find {@link FactoryBean} type information.
1991
+ */
1992
+ private static class FactoryBeanMethodTypeFinder implements MethodCallback {
1993
+
1994
+ private final String factoryMethodName ;
1995
+
1996
+ private ResolvableType result = ResolvableType .NONE ;
1997
+
1998
+
1999
+ FactoryBeanMethodTypeFinder (String factoryMethodName ) {
2000
+ this .factoryMethodName = factoryMethodName ;
2001
+ }
2002
+
2003
+
2004
+ @ Override
2005
+ public void doWith (Method method ) throws IllegalArgumentException , IllegalAccessException {
2006
+ if (isFactoryBeanMethod (method )) {
2007
+ ResolvableType returnType = ResolvableType .forMethodReturnType (method );
2008
+ ResolvableType candidate = returnType .as (FactoryBean .class ).getGeneric ();
2009
+ if (this .result == ResolvableType .NONE ) {
2010
+ this .result = candidate ;
2011
+ }
2012
+ else {
2013
+ Class <?> resolvedResult = this .result .resolve ();
2014
+ Class <?> commonAncestor = ClassUtils .determineCommonAncestor (candidate .resolve (), resolvedResult );
2015
+ if (!ObjectUtils .nullSafeEquals (resolvedResult , commonAncestor )) {
2016
+ this .result = ResolvableType .forClass (commonAncestor );
2017
+ }
2018
+ }
2019
+ }
2020
+ }
2021
+
2022
+ private boolean isFactoryBeanMethod (Method method ) {
2023
+ return method .getName ().equals (this .factoryMethodName ) &&
2024
+ FactoryBean .class .isAssignableFrom (method .getReturnType ());
2025
+ }
2026
+
2027
+
2028
+ ResolvableType getResult () {
2029
+ Class <?> resolved = this .result .resolve ();
2030
+ boolean foundResult = resolved != null && resolved != Object .class ;
2031
+ return (foundResult ? this .result : ResolvableType .NONE );
2032
+ }
2033
+
2034
+ }
2035
+
1986
2036
}
0 commit comments