1717import java .lang .reflect .Type ;
1818import java .lang .reflect .TypeVariable ;
1919import java .util .Arrays ;
20+ import java .util .LinkedHashMap ;
2021import java .util .List ;
22+ import java .util .Map ;
2123import java .util .Objects ;
2224import java .util .Optional ;
2325import java .util .stream .Collectors ;
@@ -155,7 +157,7 @@ public static boolean isKotlinClass(Class<?> cls) {
155157 public Type getFieldType (Field field ) {
156158 final KProperty <?> kProperty = ReflectJvmMapping .getKotlinProperty (field );
157159 if (kProperty != null ) {
158- return getType (kProperty .getReturnType ());
160+ return getType (kProperty .getReturnType (), new LinkedHashMap <>() );
159161 }
160162 return javaTypeParser .getFieldType (field );
161163 }
@@ -164,7 +166,7 @@ public Type getFieldType(Field field) {
164166 public Type getMethodReturnType (Method method ) {
165167 final KFunction <?> kFunction = ReflectJvmMapping .getKotlinFunction (method );
166168 if (kFunction != null ) {
167- return getType (kFunction .getReturnType ());
169+ return getType (kFunction .getReturnType (), new LinkedHashMap <>() );
168170 } else {
169171 // `method` might be a getter so try to find a corresponding field and pass it to Kotlin reflection
170172 final KClass <?> kClass = JvmClassMappingKt .getKotlinClass (method .getDeclaringClass ());
@@ -187,23 +189,25 @@ public List<Type> getMethodParameterTypes(Method method) {
187189 final List <KParameter > kParameters = kFunction .getParameters ().stream ()
188190 .filter (kParameter -> kParameter .getKind () == KParameter .Kind .VALUE )
189191 .collect (Collectors .toList ());
190- return getTypes (kParameters .stream ()
191- .map (parameter -> parameter .getType ())
192- .collect (Collectors .toList ())
192+ return getTypes (
193+ kParameters .stream ()
194+ .map (parameter -> parameter .getType ())
195+ .collect (Collectors .toList ()),
196+ new LinkedHashMap <>()
193197 );
194198 }
195199 return javaTypeParser .getMethodParameterTypes (method );
196200 }
197201
198- private Type getType (KType kType ) {
202+ private Type getType (KType kType , Map < String , JTypeVariable <?>> typeParameters ) {
199203 if (kType == null ) {
200204 return new JWildcardType ();
201205 }
202- final Type type = getBareType (kType );
206+ final Type type = getBareType (kType , typeParameters );
203207 return new JTypeWithNullability (type , kType .isMarkedNullable ());
204208 }
205209
206- private Type getBareType (KType kType ) {
210+ private Type getBareType (KType kType , Map < String , JTypeVariable <?>> typeParameters ) {
207211 final KClassifier kClassifier = kType .getClassifier ();
208212 if (kClassifier instanceof KClass ) {
209213 final KClass <?> kClass = (KClass <?>) kClassifier ;
@@ -215,33 +219,41 @@ private Type getBareType(KType kType) {
215219 if (arguments .isEmpty ()) {
216220 return javaClass ;
217221 } else if (javaClass .isArray ()) {
218- return new JGenericArrayType (getType (arguments .get (0 ).getType ()));
222+ return new JGenericArrayType (getType (arguments .get (0 ).getType (), typeParameters ));
219223 } else {
220224 final List <Type > javaArguments = arguments .stream ()
221- .map (argument -> getType (argument .getType ()))
225+ .map (argument -> getType (argument .getType (), typeParameters ))
222226 .collect (Collectors .toList ());
223227 return Utils .createParameterizedType (javaClass , javaArguments );
224228 }
225229 }
226230 if (kClassifier instanceof KTypeParameter ) {
227231 final KTypeParameter kTypeParameter = (KTypeParameter ) kClassifier ;
228- final TypeVariable <?> typeVariable = getJavaTypeVariable (kType );
229- final Type [] bounds = getTypes (kTypeParameter .getUpperBounds ()).toArray (new Type [0 ]);
230- return new JTypeVariable <>(
231- typeVariable != null ? typeVariable .getGenericDeclaration () : null ,
232- kTypeParameter .getName (),
233- bounds ,
234- typeVariable != null ? typeVariable .getAnnotatedBounds () : null ,
235- typeVariable != null ? typeVariable .getAnnotations () : null ,
236- typeVariable != null ? typeVariable .getDeclaredAnnotations () : null
237- );
232+ final JTypeVariable <?> typeVariableFromMap = typeParameters .get (kTypeParameter .getName ());
233+ if (typeVariableFromMap != null ) {
234+ return typeVariableFromMap ;
235+ } else {
236+ final TypeVariable <?> typeVariable = getJavaTypeVariable (kType );
237+ final JTypeVariable <?> newTypeVariable = new JTypeVariable <>(
238+ typeVariable != null ? typeVariable .getGenericDeclaration () : null ,
239+ kTypeParameter .getName (),
240+ /*bounds*/ null ,
241+ typeVariable != null ? typeVariable .getAnnotatedBounds () : null ,
242+ typeVariable != null ? typeVariable .getAnnotations () : null ,
243+ typeVariable != null ? typeVariable .getDeclaredAnnotations () : null
244+ );
245+ typeParameters .put (kTypeParameter .getName (), newTypeVariable );
246+ final Type [] bounds = getTypes (kTypeParameter .getUpperBounds (), typeParameters ).toArray (new Type [0 ]);
247+ newTypeVariable .setBounds (bounds );
248+ return newTypeVariable ;
249+ }
238250 }
239251 throw new RuntimeException ("Unexpected type: " + kType .toString ());
240252 }
241253
242- private List <Type > getTypes (List <KType > kTypes ) {
254+ private List <Type > getTypes (List <KType > kTypes , Map < String , JTypeVariable <?>> typeParameters ) {
243255 return kTypes .stream ()
244- .map (kType -> getType (kType ))
256+ .map (kType -> getType (kType , typeParameters ))
245257 .collect (Collectors .toList ());
246258 }
247259
0 commit comments