1616
1717package org .springframework .ai .model .function ;
1818
19- import java .lang .reflect .GenericArrayType ;
20- import java .lang .reflect .ParameterizedType ;
2119import java .lang .reflect .Type ;
2220import java .util .function .BiFunction ;
2321import java .util .function .Function ;
2422
25- import net .jodah .typetools .TypeResolver ;
23+ import kotlin .jvm .functions .Function1 ;
24+ import kotlin .jvm .functions .Function2 ;
2625
27- import org .springframework .cloud .function .context .catalog .FunctionTypeUtils ;
26+ import org .springframework .core .KotlinDetector ;
27+ import org .springframework .core .ResolvableType ;
2828
2929/**
3030 * A utility class that provides methods for resolving types and classes related to
3131 * functions.
3232 *
3333 * @author Christian Tzolov
34+ * @author Sebastien Dekeuze
3435 */
3536public abstract class TypeResolverHelper {
3637
@@ -68,12 +69,9 @@ public static Class<?> getFunctionOutputClass(Class<? extends Function<?, ?>> fu
6869 * @return The class of the specified function argument.
6970 */
7071 public static Class <?> getFunctionArgumentClass (Class <? extends Function <?, ?>> functionClass , int argumentIndex ) {
71- Type type = TypeResolver .reify (Function .class , functionClass );
72-
73- var argumentType = type instanceof ParameterizedType
74- ? ((ParameterizedType ) type ).getActualTypeArguments ()[argumentIndex ] : Object .class ;
75-
76- return toRawClass (argumentType );
72+ ResolvableType resolvableType = ResolvableType .forClass (functionClass ).as (Function .class );
73+ return (resolvableType == ResolvableType .NONE ? Object .class
74+ : resolvableType .getGeneric (argumentIndex ).toClass ());
7775 }
7876
7977 /**
@@ -84,80 +82,65 @@ public static Class<?> getFunctionArgumentClass(Class<? extends Function<?, ?>>
8482 */
8583 public static Class <?> getBiFunctionArgumentClass (Class <? extends BiFunction <?, ?, ?>> biFunctionClass ,
8684 int argumentIndex ) {
87- Type type = TypeResolver .reify (BiFunction .class , biFunctionClass );
88-
89- Type argumentType = type instanceof ParameterizedType
90- ? ((ParameterizedType ) type ).getActualTypeArguments ()[argumentIndex ] : Object .class ;
91-
92- return toRawClass (argumentType );
93- }
94-
95- /**
96- * Returns the input type of a given function class.
97- * @param functionClass The class of the function.
98- * @return The input type of the function.
99- */
100- public static Type getFunctionInputType (Class <? extends Function <?, ?>> functionClass ) {
101- return getFunctionArgumentType (functionClass , 0 );
102- }
103-
104- /**
105- * Retrieves the output type of a given function class.
106- * @param functionClass The function class.
107- * @return The output type of the function.
108- */
109- public static Type getFunctionOutputType (Class <? extends Function <?, ?>> functionClass ) {
110- return getFunctionArgumentType (functionClass , 1 );
85+ ResolvableType resolvableType = ResolvableType .forClass (biFunctionClass ).as (BiFunction .class );
86+ return (resolvableType == ResolvableType .NONE ? Object .class
87+ : resolvableType .getGeneric (argumentIndex ).toClass ());
11188 }
11289
11390 /**
11491 * Retrieves the type of a specific argument in a given function class.
115- * @param functionClass The function class.
116- * @param argumentIndex The index of the argument whose type should be retrieved.
117- * @return The type of the specified function argument.
118- */
119- public static Type getFunctionArgumentType (Class <? extends Function <?, ?>> functionClass , int argumentIndex ) {
120- Type functionType = TypeResolver .reify (Function .class , functionClass );
121- return getFunctionArgumentType (functionType , argumentIndex );
122- }
123-
124- /**
125- * Retrieves the type of a specific argument in a given function type.
12692 * @param functionType The function type.
12793 * @param argumentIndex The index of the argument whose type should be retrieved.
12894 * @return The type of the specified function argument.
95+ * @throws IllegalArgumentException if functionType is not a supported type
12996 */
130- public static Type getFunctionArgumentType (Type functionType , int argumentIndex ) {
131-
132- // Resolves: https://github.com/spring-projects/spring-ai/issues/726
133- if (!(functionType instanceof ParameterizedType )) {
134- Class <?> functionalClass = FunctionTypeUtils .getRawType (functionType );
135- // Resolves: https://github.com/spring-projects/spring-ai/issues/1576
136- if (BiFunction .class .isAssignableFrom (functionalClass )) {
137- functionType = TypeResolver .reify (BiFunction .class , (Class <BiFunction <?, ?, ?>>) functionalClass );
97+ public static ResolvableType getFunctionArgumentType (Type functionType , int argumentIndex ) {
98+
99+ ResolvableType resolvableType = ResolvableType .forType (functionType );
100+ Class <?> resolvableClass = resolvableType .toClass ();
101+ ResolvableType functionArgumentResolvableType = ResolvableType .NONE ;
102+
103+ if (Function .class .isAssignableFrom (resolvableClass )) {
104+ functionArgumentResolvableType = resolvableType .as (Function .class );
105+ }
106+ else if (BiFunction .class .isAssignableFrom (resolvableClass )) {
107+ functionArgumentResolvableType = resolvableType .as (BiFunction .class );
108+ }
109+ else if (KotlinDetector .isKotlinPresent ()) {
110+ if (KotlinDelegate .isKotlinFunction (resolvableClass )) {
111+ functionArgumentResolvableType = KotlinDelegate .adaptToKotlinFunctionType (resolvableType );
138112 }
139- else {
140- functionType = FunctionTypeUtils . discoverFunctionTypeFromClass ( functionalClass );
113+ else if ( KotlinDelegate . isKotlinBiFunction ( resolvableClass )) {
114+ functionArgumentResolvableType = KotlinDelegate . adaptToKotlinBiFunctionType ( resolvableType );
141115 }
142116 }
143117
144- var argumentType = functionType instanceof ParameterizedType
145- ? ((ParameterizedType ) functionType ).getActualTypeArguments ()[argumentIndex ] : Object .class ;
118+ if (functionArgumentResolvableType == ResolvableType .NONE ) {
119+ throw new IllegalArgumentException (
120+ "Type must be a Function, BiFunction, Function1 or Function2. Found: " + resolvableType );
121+ }
146122
147- return argumentType ;
123+ return functionArgumentResolvableType . getGeneric ( argumentIndex ) ;
148124 }
149125
150- /**
151- * Effectively converts {@link Type} which could be {@link ParameterizedType} to raw
152- * Class (no generics).
153- * @param type actual {@link Type} instance
154- * @return instance of {@link Class} as raw representation of the provided
155- * {@link Type}
156- */
157- public static Class <?> toRawClass (Type type ) {
158- return type != null
159- ? TypeResolver .resolveRawClass (type instanceof GenericArrayType ? type : TypeResolver .reify (type ), null )
160- : null ;
126+ private static class KotlinDelegate {
127+
128+ public static boolean isKotlinFunction (Class <?> clazz ) {
129+ return Function1 .class .isAssignableFrom (clazz );
130+ }
131+
132+ public static ResolvableType adaptToKotlinFunctionType (ResolvableType resolvableType ) {
133+ return resolvableType .as (Function1 .class );
134+ }
135+
136+ public static boolean isKotlinBiFunction (Class <?> clazz ) {
137+ return Function2 .class .isAssignableFrom (clazz );
138+ }
139+
140+ public static ResolvableType adaptToKotlinBiFunctionType (ResolvableType resolvableType ) {
141+ return resolvableType .as (Function2 .class );
142+ }
143+
161144 }
162145
163146}
0 commit comments