7373import org .springframework .util .StringUtils ;
7474
7575
76-
7776/**
7877 * Set of utility operations to interrogate function definitions.
7978 *
@@ -95,17 +94,17 @@ private FunctionTypeUtils() {
9594
9695 public static Type functionType (Type input , Type output ) {
9796 return ResolvableType .forClassWithGenerics (Function .class ,
98- ResolvableType .forType (input ), ResolvableType .forType (output )).getType ();
97+ ResolvableType .forType (input ), ResolvableType .forType (output )).getType ();
9998 }
10099
101100 public static Type consumerType (Type input ) {
102101 return ResolvableType .forClassWithGenerics (Consumer .class ,
103- ResolvableType .forType (input )).getType ();
102+ ResolvableType .forType (input )).getType ();
104103 }
105104
106105 public static Type supplierType (Type output ) {
107106 return ResolvableType .forClassWithGenerics (Supplier .class ,
108- ResolvableType .forType (output )).getType ();
107+ ResolvableType .forType (output )).getType ();
109108 }
110109
111110 /**
@@ -180,7 +179,7 @@ public static Class<?> getRawType(Type type) {
180179 */
181180 return ObjectUtils .isEmpty (upperbounds ) ? Object .class : getRawType (upperbounds [0 ]);
182181 }
183- return ResolvableType .forType (type ).getRawClass ();
182+ return ResolvableType .forType (type ).getRawClass () == null ? Object . class : ResolvableType . forType ( type ). getRawClass () ;
184183 }
185184
186185 /**
@@ -195,15 +194,15 @@ public static Class<?> getRawType(Type type) {
195194 public static Method discoverFunctionalMethod (Class <?> pojoFunctionClass ) {
196195 if (Supplier .class .isAssignableFrom (pojoFunctionClass )) {
197196 return Stream .of (ReflectionUtils .getAllDeclaredMethods (pojoFunctionClass )).filter (m -> !m .isSynthetic ()
198- && m .getName ().equals ("get" )).findFirst ().get ();
197+ && m .getName ().equals ("get" )).findFirst ().get ();
199198 }
200199 else if (Consumer .class .isAssignableFrom (pojoFunctionClass ) || BiConsumer .class .isAssignableFrom (pojoFunctionClass )) {
201200 return Stream .of (ReflectionUtils .getAllDeclaredMethods (pojoFunctionClass )).filter (m -> !m .isSynthetic ()
202- && m .getName ().equals ("accept" )).findFirst ().get ();
201+ && m .getName ().equals ("accept" )).findFirst ().get ();
203202 }
204203 else if (Function .class .isAssignableFrom (pojoFunctionClass ) || BiFunction .class .isAssignableFrom (pojoFunctionClass )) {
205204 return Stream .of (ReflectionUtils .getAllDeclaredMethods (pojoFunctionClass )).filter (m -> !m .isSynthetic ()
206- && m .getName ().equals ("apply" )).findFirst ().get ();
205+ && m .getName ().equals ("apply" )).findFirst ().get ();
207206 }
208207
209208 List <Method > methods = new ArrayList <>();
@@ -214,7 +213,7 @@ else if (Function.class.isAssignableFrom(pojoFunctionClass) || BiFunction.class.
214213
215214 }, method ->
216215 !method .getDeclaringClass ().isAssignableFrom (Object .class )
217- && !method .isSynthetic () && !method .isBridge () && !method .isVarArgs ());
216+ && !method .isSynthetic () && !method .isBridge () && !method .isVarArgs ());
218217
219218 if (methods .size () > 1 ) {
220219 for (Method candidadteMethod : methods ) {
@@ -229,6 +228,28 @@ else if (Function.class.isAssignableFrom(pojoFunctionClass) || BiFunction.class.
229228 return CollectionUtils .isEmpty (methods ) ? null : methods .get (0 );
230229 }
231230
231+ public static Type discoverFunctionTypeFromType (Type functionalType ) {
232+ Type typeToReturn = null ;
233+ if (Function .class .isAssignableFrom (getRawType (functionalType ))) {
234+ ResolvableType functionType = ResolvableType .forType (functionalType ).as (Function .class );
235+ typeToReturn = GenericTypeResolver .resolveType (functionType .getType (), getRawType (functionalType ));
236+ }
237+ else if (Consumer .class .isAssignableFrom (getRawType (functionalType ))) {
238+ ResolvableType functionType = ResolvableType .forType (functionalType ).as (Consumer .class );
239+
240+ ResolvableType t = ResolvableType .forClassWithGenerics (getRawType (functionalType ), functionType .getGeneric (0 ));
241+ Type t2 = t .getType ();
242+ //Type t = ResolvableType.
243+
244+ typeToReturn = GenericTypeResolver .resolveType (functionType .getType (), functionType .getRawClass ());
245+ }
246+ else {
247+ ResolvableType functionType = ResolvableType .forType (functionalType ).as (Supplier .class );
248+ typeToReturn = GenericTypeResolver .resolveType (functionType .getType (), getRawType (functionalType ));
249+ }
250+ return typeToReturn ;
251+ }
252+
232253 public static Type discoverFunctionTypeFromClass (Class <?> functionalClass ) {
233254 if (KotlinDetector .isKotlinPresent ()) {
234255 if (Function1 .class .isAssignableFrom (functionalClass )) {
@@ -249,15 +270,15 @@ else if (Function0.class.isAssignableFrom(functionalClass)) {
249270 }
250271 }
251272 }
252- ResolvableType functionType = ResolvableType .forClass (functionalClass ).as (Function .class );
273+ ResolvableType functionType = ResolvableType .forType (functionalClass ).as (Function .class );
253274 typeToReturn = GenericTypeResolver .resolveType (functionType .getType (), functionalClass );
254275 }
255276 else if (Consumer .class .isAssignableFrom (functionalClass )) {
256- ResolvableType functionType = ResolvableType .forClass (functionalClass ).as (Consumer .class );
277+ ResolvableType functionType = ResolvableType .forType (functionalClass ).as (Consumer .class );
257278 typeToReturn = GenericTypeResolver .resolveType (functionType .getType (), functionalClass );
258279 }
259280 else if (Supplier .class .isAssignableFrom (functionalClass )) {
260- ResolvableType functionType = ResolvableType .forClass (functionalClass ).as (Supplier .class );
281+ ResolvableType functionType = ResolvableType .forType (functionalClass ).as (Supplier .class );
261282 typeToReturn = GenericTypeResolver .resolveType (functionType .getType (), functionalClass );
262283 }
263284 return typeToReturn ;
@@ -286,6 +307,7 @@ public static Type discoverFunctionTypeFromFunctionFactoryMethod(Class<?> clazz,
286307 */
287308 public static Type discoverFunctionTypeFromFunctionFactoryMethod (Method method ) {
288309 return method .getGenericReturnType ();
310+ // return discoverFunctionTypeFromClass(method.getReturnType());
289311 }
290312
291313 /**
@@ -299,11 +321,11 @@ public static Type discoverFunctionTypeFromFunctionMethod(Method functionMethod)
299321 return null ;
300322 }
301323 Assert .isTrue (
302- functionMethod .getName ().equals ("apply" ) ||
324+ functionMethod .getName ().equals ("apply" ) ||
303325 functionMethod .getName ().equals ("accept" ) ||
304326 functionMethod .getName ().equals ("get" ) ||
305327 functionMethod .getName ().equals ("invoke" ),
306- "Only Supplier, Function or Consumer supported at the moment. Was " + functionMethod .getDeclaringClass ());
328+ "Only Supplier, Function or Consumer supported at the moment. Was " + functionMethod .getDeclaringClass ());
307329
308330 ResolvableType functionType ;
309331 if (functionMethod .getName ().equals ("apply" ) || functionMethod .getName ().equals ("invoke" )) {
@@ -376,6 +398,49 @@ public static Type getComponentTypeOfOutputType(Type functionType) {
376398 return getImmediateGenericType (inputType , 0 );
377399 }
378400
401+ /**
402+ * Will resolve @{@link ResolvableType} to {@link Type} preserving all the resolved generics.
403+ * @param typeWithGenerics - instance of {@link ResolvableType}.
404+ * @return - {@link Type} representation of the provided {@link ResolvableType}.
405+ */
406+ public static Type resolveType (ResolvableType typeWithGenerics ) {
407+ if (typeWithGenerics .hasResolvableGenerics ()) {
408+ ResolvableType [] generics = typeWithGenerics .getGenerics ();
409+ List <ResolvableType > resolvedGenerics = new ArrayList <>();
410+ for (int i = 0 ; i < generics .length ; i ++) {
411+ ResolvableType genericType = typeWithGenerics .getGenerics ()[i ];
412+ resolvedGenerics .add (ResolvableType .forType (resolveType (genericType )));
413+ }
414+ return ResolvableType .forClassWithGenerics (typeWithGenerics .getRawClass (),
415+ resolvedGenerics .toArray (new ResolvableType [0 ])).getType ();
416+ }
417+ else {
418+ return typeWithGenerics .resolve ();
419+ }
420+ }
421+
422+ public static Type getOutputType (Type functionType ) {
423+ assertSupportedTypes (functionType );
424+ if (isConsumer (functionType )) {
425+ logger .debug ("Consumer does not have output type, returning null as output type." );
426+ return null ;
427+ }
428+
429+ if (KotlinDetector .isKotlinPresent () && Function1 .class .isAssignableFrom (getRawType (functionType ))) { // Kotlin
430+ return ResolvableType .forType (getImmediateGenericType (functionType , 1 )).getType ();
431+ }
432+ else {
433+ ResolvableType resolvableFunctionType = isSupplier (functionType )
434+ ? ResolvableType .forType (functionType ).as (Supplier .class )
435+ : ResolvableType .forType (functionType ).as (Function .class );
436+ ResolvableType generics = isSupplier (functionType )
437+ ? resolvableFunctionType .getGenerics ()[0 ]
438+ : resolvableFunctionType .getGenerics ()[1 ];
439+ Type outputType = FunctionTypeUtils .resolveType (generics );
440+ return outputType == null || outputType instanceof TypeVariable <?> ? Object .class : outputType ;
441+ }
442+ }
443+
379444 /**
380445 * Returns input type of function type that represents Function or Consumer.
381446 * @param functionType the Type of Function or Consumer
@@ -388,35 +453,17 @@ public static Type getInputType(Type functionType) {
388453 return null ;
389454 }
390455
391- ResolvableType resolvableFunctionType = ResolvableType .forType (functionType );
392-
393- if (FunctionTypeUtils .isFunction (functionType )) {
394- return extractInputType (resolvableFunctionType .as (Function .class ).getGeneric (0 ));
395- }
396- if (FunctionTypeUtils .isConsumer (functionType )) {
397- return extractInputType (resolvableFunctionType .as (Consumer .class ).getGeneric (0 ));
398- }
399456 if (KotlinDetector .isKotlinPresent () && Function1 .class .isAssignableFrom (getRawType (functionType ))) { // Kotlin
400457 return ResolvableType .forType (getImmediateGenericType (functionType , 1 )).getType ();
401458 }
402-
403- // no consumer or function
404- // might be one of the other supported types (as asserted in first line of method)
405- // for example FunctionRegistration or IntConsumer
406-
407- // unclear what the contract is in such a case
408- // maybe returning null here might be "more" correct
409- return Object .class ;
410- }
411-
412- private static Type extractInputType (ResolvableType resolvableInputType ) {
413- if (resolvableInputType .getType () instanceof TypeVariable ) {
414- // In case the input type is a type variable (e.g. as in GH-1251) we need to resolve the type
415- // For the case that the type is unbound Object.class is used
416- return resolvableInputType .resolve (Object .class );
459+ else {
460+ ResolvableType resolvableFunctionType = isConsumer (functionType )
461+ ? ResolvableType .forType (functionType ).as (Consumer .class )
462+ : ResolvableType .forType (functionType ).as (Function .class );
463+ ResolvableType generics = resolvableFunctionType .getGenerics ()[0 ];
464+ Type inputType = FunctionTypeUtils .resolveType (generics );
465+ return inputType == null || inputType instanceof TypeVariable <?> ? Object .class : inputType ;
417466 }
418-
419- return resolvableInputType .getType ();
420467 }
421468
422469 @ SuppressWarnings ("rawtypes" )
@@ -429,7 +476,7 @@ else if (function instanceof FunctionRegistration) {
429476 }
430477 if (applicationContext .containsBean (functionName + FunctionRegistration .REGISTRATION_NAME_SUFFIX )) { // for Kotlin primarily
431478 FunctionRegistration fr = applicationContext
432- .getBean (functionName + FunctionRegistration .REGISTRATION_NAME_SUFFIX , FunctionRegistration .class );
479+ .getBean (functionName + FunctionRegistration .REGISTRATION_NAME_SUFFIX , FunctionRegistration .class );
433480 return fr .getType ();
434481 }
435482
@@ -478,52 +525,6 @@ public static String discoverBeanDefinitionNameByQualifier(ListableBeanFactory b
478525 }
479526 return null ;
480527 }
481-
482- public static Type getOutputType (Type functionType ) {
483- assertSupportedTypes (functionType );
484- if (isConsumer (functionType )) {
485- logger .debug ("Consumer does not have output type, returning null as output type." );
486- return null ;
487- }
488-
489- ResolvableType resolvableFunctionType = ResolvableType .forType (functionType );
490-
491- ResolvableType resolvableOutputType ;
492- if (FunctionTypeUtils .isFunction (functionType )) {
493- resolvableOutputType = resolvableFunctionType .as (Function .class );
494- }
495- else {
496- if (KotlinDetector .isKotlinPresent () && Function1 .class .isAssignableFrom (getRawType (functionType ))) { // Kotlin
497- return ResolvableType .forType (getImmediateGenericType (functionType , 1 )).getType ();
498- }
499- else {
500- resolvableOutputType = resolvableFunctionType .as (Supplier .class );
501- }
502- }
503-
504- Type outputType ;
505- if (functionType instanceof Class functionTypeClass ) {
506- if (FunctionTypeUtils .isFunction (functionType )) {
507- ResolvableType genericClass1 = resolvableOutputType .getGeneric (1 );
508- outputType = genericClass1 .getType ();
509- outputType = (outputType instanceof TypeVariable ) ? Object .class : GenericTypeResolver .resolveType (outputType , functionTypeClass );
510- }
511- else {
512- ResolvableType genericClass0 = resolvableOutputType .getGeneric (0 );
513- outputType = genericClass0 .getType ();
514- outputType = (outputType instanceof TypeVariable ) ? Object .class : GenericTypeResolver .resolveType (outputType , functionTypeClass );
515- }
516- }
517- else if (functionType instanceof ParameterizedType ) {
518- Type genericType = isSupplier (functionType ) ? resolvableOutputType .getGeneric (0 ).getType () : resolvableOutputType .getGeneric (1 ).getType ();
519- outputType = GenericTypeResolver .resolveType (genericType , getRawType (functionType ));
520- }
521- else {
522- outputType = resolvableOutputType .getType ();
523- }
524- return outputType instanceof TypeVariable ? Object .class : outputType ;
525- }
526-
527528 public static Type getImmediateGenericType (Type type , int index ) {
528529 if (type instanceof ParameterizedType ) {
529530 return ((ParameterizedType ) type ).getActualTypeArguments ()[index ];
@@ -613,23 +614,23 @@ static Type fromFunctionMethod(Method functionalMethod) {
613614
614615 Type functionType = null ;
615616 switch (parameterTypes .length ) {
616- case 0 :
617- functionType = ResolvableType .forClassWithGenerics (Supplier .class ,
617+ case 0 :
618+ functionType = ResolvableType .forClassWithGenerics (Supplier .class ,
618619 ResolvableType .forMethodReturnType (functionalMethod )).getType ();
619- break ;
620- case 1 :
621- if (Void .class .isAssignableFrom (functionalMethod .getReturnType ())) {
622- functionType = ResolvableType .forClassWithGenerics (Consumer .class ,
620+ break ;
621+ case 1 :
622+ if (Void .class .isAssignableFrom (functionalMethod .getReturnType ())) {
623+ functionType = ResolvableType .forClassWithGenerics (Consumer .class ,
623624 ResolvableType .forMethodParameter (functionalMethod , 0 )).getType ();
624- }
625- else {
626- functionType = ResolvableType .forClassWithGenerics (Function .class ,
625+ }
626+ else {
627+ functionType = ResolvableType .forClassWithGenerics (Function .class ,
627628 ResolvableType .forMethodParameter (functionalMethod , 0 ),
628629 ResolvableType .forMethodReturnType (functionalMethod )).getType ();
629- }
630- break ;
631- default :
632- throw new UnsupportedOperationException ("Functional method: " + functionalMethod + " is not supported" );
630+ }
631+ break ;
632+ default :
633+ throw new UnsupportedOperationException ("Functional method: " + functionalMethod + " is not supported" );
633634 }
634635 return functionType ;
635636 }
@@ -652,31 +653,31 @@ private static void assertSupportedTypes(Type type) {
652653 if (type instanceof ParameterizedType ) {
653654 type = ((ParameterizedType ) type ).getRawType ();
654655 Assert .isTrue (type instanceof Class <?>, "Must be one of Supplier, Function, Consumer"
655- + " or FunctionRegistration. Was " + type );
656+ + " or FunctionRegistration. Was " + type );
656657 }
657658
658659 Class <?> candidateType = (Class <?>) type ;
659660
660661 Assert .isTrue (Supplier .class .isAssignableFrom (candidateType )
661- || (KotlinDetector .isKotlinPresent () && (Function0 .class .isAssignableFrom (candidateType ) || Function1 .class .isAssignableFrom (candidateType )))
662- || Function .class .isAssignableFrom (candidateType )
663- || Consumer .class .isAssignableFrom (candidateType )
664- || FunctionRegistration .class .isAssignableFrom (candidateType )
665- || IntConsumer .class .isAssignableFrom (candidateType )
666- || IntSupplier .class .isAssignableFrom (candidateType )
667- || IntFunction .class .isAssignableFrom (candidateType )
668- || ToIntFunction .class .isAssignableFrom (candidateType )
669- || LongConsumer .class .isAssignableFrom (candidateType )
670- || LongSupplier .class .isAssignableFrom (candidateType )
671- || LongFunction .class .isAssignableFrom (candidateType )
672- || ToLongFunction .class .isAssignableFrom (candidateType )
673- || DoubleConsumer .class .isAssignableFrom (candidateType )
674- || DoubleSupplier .class .isAssignableFrom (candidateType )
675- || DoubleFunction .class .isAssignableFrom (candidateType )
676- || ToDoubleFunction .class .isAssignableFrom (candidateType )
677- || type .getTypeName ().startsWith ("org.springframework.context.annotation.ConfigurationClassEnhancer" ),
678- "Must be one of Supplier, Function, Consumer"
679- + " or FunctionRegistration. Was " + type );
662+ || (KotlinDetector .isKotlinPresent () && (Function0 .class .isAssignableFrom (candidateType ) || Function1 .class .isAssignableFrom (candidateType )))
663+ || Function .class .isAssignableFrom (candidateType )
664+ || Consumer .class .isAssignableFrom (candidateType )
665+ || FunctionRegistration .class .isAssignableFrom (candidateType )
666+ || IntConsumer .class .isAssignableFrom (candidateType )
667+ || IntSupplier .class .isAssignableFrom (candidateType )
668+ || IntFunction .class .isAssignableFrom (candidateType )
669+ || ToIntFunction .class .isAssignableFrom (candidateType )
670+ || LongConsumer .class .isAssignableFrom (candidateType )
671+ || LongSupplier .class .isAssignableFrom (candidateType )
672+ || LongFunction .class .isAssignableFrom (candidateType )
673+ || ToLongFunction .class .isAssignableFrom (candidateType )
674+ || DoubleConsumer .class .isAssignableFrom (candidateType )
675+ || DoubleSupplier .class .isAssignableFrom (candidateType )
676+ || DoubleFunction .class .isAssignableFrom (candidateType )
677+ || ToDoubleFunction .class .isAssignableFrom (candidateType )
678+ || type .getTypeName ().startsWith ("org.springframework.context.annotation.ConfigurationClassEnhancer" ),
679+ "Must be one of Supplier, Function, Consumer"
680+ + " or FunctionRegistration. Was " + type );
680681 }
681682
682683 private static Type extractReactiveType (Type type ) {
0 commit comments