7373import org .springframework .util .StringUtils ;
7474
7575
76+
7677/**
7778 * Set of utility operations to interrogate function definitions.
7879 *
@@ -94,17 +95,17 @@ private FunctionTypeUtils() {
9495
9596 public static Type functionType (Type input , Type output ) {
9697 return ResolvableType .forClassWithGenerics (Function .class ,
97- ResolvableType .forType (input ), ResolvableType .forType (output )).getType ();
98+ ResolvableType .forType (input ), ResolvableType .forType (output )).getType ();
9899 }
99100
100101 public static Type consumerType (Type input ) {
101102 return ResolvableType .forClassWithGenerics (Consumer .class ,
102- ResolvableType .forType (input )).getType ();
103+ ResolvableType .forType (input )).getType ();
103104 }
104105
105106 public static Type supplierType (Type output ) {
106107 return ResolvableType .forClassWithGenerics (Supplier .class ,
107- ResolvableType .forType (output )).getType ();
108+ ResolvableType .forType (output )).getType ();
108109 }
109110
110111 /**
@@ -179,7 +180,7 @@ public static Class<?> getRawType(Type type) {
179180 */
180181 return ObjectUtils .isEmpty (upperbounds ) ? Object .class : getRawType (upperbounds [0 ]);
181182 }
182- return ResolvableType .forType (type ).getRawClass () == null ? Object . class : ResolvableType . forType ( type ). getRawClass () ;
183+ return ResolvableType .forType (type ).getRawClass ();
183184 }
184185
185186 /**
@@ -194,15 +195,15 @@ public static Class<?> getRawType(Type type) {
194195 public static Method discoverFunctionalMethod (Class <?> pojoFunctionClass ) {
195196 if (Supplier .class .isAssignableFrom (pojoFunctionClass )) {
196197 return Stream .of (ReflectionUtils .getAllDeclaredMethods (pojoFunctionClass )).filter (m -> !m .isSynthetic ()
197- && m .getName ().equals ("get" )).findFirst ().get ();
198+ && m .getName ().equals ("get" )).findFirst ().get ();
198199 }
199200 else if (Consumer .class .isAssignableFrom (pojoFunctionClass ) || BiConsumer .class .isAssignableFrom (pojoFunctionClass )) {
200201 return Stream .of (ReflectionUtils .getAllDeclaredMethods (pojoFunctionClass )).filter (m -> !m .isSynthetic ()
201- && m .getName ().equals ("accept" )).findFirst ().get ();
202+ && m .getName ().equals ("accept" )).findFirst ().get ();
202203 }
203204 else if (Function .class .isAssignableFrom (pojoFunctionClass ) || BiFunction .class .isAssignableFrom (pojoFunctionClass )) {
204205 return Stream .of (ReflectionUtils .getAllDeclaredMethods (pojoFunctionClass )).filter (m -> !m .isSynthetic ()
205- && m .getName ().equals ("apply" )).findFirst ().get ();
206+ && m .getName ().equals ("apply" )).findFirst ().get ();
206207 }
207208
208209 List <Method > methods = new ArrayList <>();
@@ -213,7 +214,7 @@ else if (Function.class.isAssignableFrom(pojoFunctionClass) || BiFunction.class.
213214
214215 }, method ->
215216 !method .getDeclaringClass ().isAssignableFrom (Object .class )
216- && !method .isSynthetic () && !method .isBridge () && !method .isVarArgs ());
217+ && !method .isSynthetic () && !method .isBridge () && !method .isVarArgs ());
217218
218219 if (methods .size () > 1 ) {
219220 for (Method candidadteMethod : methods ) {
@@ -228,28 +229,6 @@ else if (Function.class.isAssignableFrom(pojoFunctionClass) || BiFunction.class.
228229 return CollectionUtils .isEmpty (methods ) ? null : methods .get (0 );
229230 }
230231
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-
253232 public static Type discoverFunctionTypeFromClass (Class <?> functionalClass ) {
254233 if (KotlinDetector .isKotlinPresent ()) {
255234 if (Function1 .class .isAssignableFrom (functionalClass )) {
@@ -270,15 +249,15 @@ else if (Function0.class.isAssignableFrom(functionalClass)) {
270249 }
271250 }
272251 }
273- ResolvableType functionType = ResolvableType .forType (functionalClass ).as (Function .class );
252+ ResolvableType functionType = ResolvableType .forClass (functionalClass ).as (Function .class );
274253 typeToReturn = GenericTypeResolver .resolveType (functionType .getType (), functionalClass );
275254 }
276255 else if (Consumer .class .isAssignableFrom (functionalClass )) {
277- ResolvableType functionType = ResolvableType .forType (functionalClass ).as (Consumer .class );
256+ ResolvableType functionType = ResolvableType .forClass (functionalClass ).as (Consumer .class );
278257 typeToReturn = GenericTypeResolver .resolveType (functionType .getType (), functionalClass );
279258 }
280259 else if (Supplier .class .isAssignableFrom (functionalClass )) {
281- ResolvableType functionType = ResolvableType .forType (functionalClass ).as (Supplier .class );
260+ ResolvableType functionType = ResolvableType .forClass (functionalClass ).as (Supplier .class );
282261 typeToReturn = GenericTypeResolver .resolveType (functionType .getType (), functionalClass );
283262 }
284263 return typeToReturn ;
@@ -307,7 +286,6 @@ public static Type discoverFunctionTypeFromFunctionFactoryMethod(Class<?> clazz,
307286 */
308287 public static Type discoverFunctionTypeFromFunctionFactoryMethod (Method method ) {
309288 return method .getGenericReturnType ();
310- // return discoverFunctionTypeFromClass(method.getReturnType());
311289 }
312290
313291 /**
@@ -321,11 +299,11 @@ public static Type discoverFunctionTypeFromFunctionMethod(Method functionMethod)
321299 return null ;
322300 }
323301 Assert .isTrue (
324- functionMethod .getName ().equals ("apply" ) ||
302+ functionMethod .getName ().equals ("apply" ) ||
325303 functionMethod .getName ().equals ("accept" ) ||
326304 functionMethod .getName ().equals ("get" ) ||
327305 functionMethod .getName ().equals ("invoke" ),
328- "Only Supplier, Function or Consumer supported at the moment. Was " + functionMethod .getDeclaringClass ());
306+ "Only Supplier, Function or Consumer supported at the moment. Was " + functionMethod .getDeclaringClass ());
329307
330308 ResolvableType functionType ;
331309 if (functionMethod .getName ().equals ("apply" ) || functionMethod .getName ().equals ("invoke" )) {
@@ -398,49 +376,6 @@ public static Type getComponentTypeOfOutputType(Type functionType) {
398376 return getImmediateGenericType (inputType , 0 );
399377 }
400378
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-
444379 /**
445380 * Returns input type of function type that represents Function or Consumer.
446381 * @param functionType the Type of Function or Consumer
@@ -453,17 +388,35 @@ public static Type getInputType(Type functionType) {
453388 return null ;
454389 }
455390
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+ }
456399 if (KotlinDetector .isKotlinPresent () && Function1 .class .isAssignableFrom (getRawType (functionType ))) { // Kotlin
457400 return ResolvableType .forType (getImmediateGenericType (functionType , 1 )).getType ();
458401 }
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 ;
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 );
466417 }
418+
419+ return resolvableInputType .getType ();
467420 }
468421
469422 @ SuppressWarnings ("rawtypes" )
@@ -476,7 +429,7 @@ else if (function instanceof FunctionRegistration) {
476429 }
477430 if (applicationContext .containsBean (functionName + FunctionRegistration .REGISTRATION_NAME_SUFFIX )) { // for Kotlin primarily
478431 FunctionRegistration fr = applicationContext
479- .getBean (functionName + FunctionRegistration .REGISTRATION_NAME_SUFFIX , FunctionRegistration .class );
432+ .getBean (functionName + FunctionRegistration .REGISTRATION_NAME_SUFFIX , FunctionRegistration .class );
480433 return fr .getType ();
481434 }
482435
@@ -525,6 +478,52 @@ public static String discoverBeanDefinitionNameByQualifier(ListableBeanFactory b
525478 }
526479 return null ;
527480 }
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+
528527 public static Type getImmediateGenericType (Type type , int index ) {
529528 if (type instanceof ParameterizedType ) {
530529 return ((ParameterizedType ) type ).getActualTypeArguments ()[index ];
@@ -614,23 +613,23 @@ static Type fromFunctionMethod(Method functionalMethod) {
614613
615614 Type functionType = null ;
616615 switch (parameterTypes .length ) {
617- case 0 :
618- functionType = ResolvableType .forClassWithGenerics (Supplier .class ,
616+ case 0 :
617+ functionType = ResolvableType .forClassWithGenerics (Supplier .class ,
619618 ResolvableType .forMethodReturnType (functionalMethod )).getType ();
620- break ;
621- case 1 :
622- if (Void .class .isAssignableFrom (functionalMethod .getReturnType ())) {
623- functionType = ResolvableType .forClassWithGenerics (Consumer .class ,
619+ break ;
620+ case 1 :
621+ if (Void .class .isAssignableFrom (functionalMethod .getReturnType ())) {
622+ functionType = ResolvableType .forClassWithGenerics (Consumer .class ,
624623 ResolvableType .forMethodParameter (functionalMethod , 0 )).getType ();
625- }
626- else {
627- functionType = ResolvableType .forClassWithGenerics (Function .class ,
624+ }
625+ else {
626+ functionType = ResolvableType .forClassWithGenerics (Function .class ,
628627 ResolvableType .forMethodParameter (functionalMethod , 0 ),
629628 ResolvableType .forMethodReturnType (functionalMethod )).getType ();
630- }
631- break ;
632- default :
633- throw new UnsupportedOperationException ("Functional method: " + functionalMethod + " is not supported" );
629+ }
630+ break ;
631+ default :
632+ throw new UnsupportedOperationException ("Functional method: " + functionalMethod + " is not supported" );
634633 }
635634 return functionType ;
636635 }
@@ -653,31 +652,31 @@ private static void assertSupportedTypes(Type type) {
653652 if (type instanceof ParameterizedType ) {
654653 type = ((ParameterizedType ) type ).getRawType ();
655654 Assert .isTrue (type instanceof Class <?>, "Must be one of Supplier, Function, Consumer"
656- + " or FunctionRegistration. Was " + type );
655+ + " or FunctionRegistration. Was " + type );
657656 }
658657
659658 Class <?> candidateType = (Class <?>) type ;
660659
661660 Assert .isTrue (Supplier .class .isAssignableFrom (candidateType )
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 );
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 );
681680 }
682681
683682 private static Type extractReactiveType (Type type ) {
0 commit comments