Skip to content

Return correct return type for Kotlin suspending functions in MethodParameter. #1694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

konrad-kaminski
Copy link
Contributor

@konrad-kaminski konrad-kaminski commented Feb 19, 2018

Return type for Kotlin suspending functions (as returned by MethodParameter#getParameterType and MethodParameter#getgenericReturnType methods) is incorrect. The true return type is the generic parameter of the last parameter of the method.

This change modifies the behaviour of the aforementioned methods so that they work correctly for all cases.

Issue: SPR-16515

return (function != null && function.isSuspend());
}

@NonNull
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary, already the default via package level @NonNullApi.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

* Returns a return type of a method using Kotlin Reflection API.
* Introduced to support suspending functions.
*/
@NonNull
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary, already the default via package level @NonNullApi.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@NonNull
static private Class<?> getReturnType(Method method) {
if (isSuspend(method)) {
return getSuspendReturnType(method).resolve();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolve() can return null but Class<?> getReturnType(Method method) is expected to return non null values. Maybe we should use resolve(Class<?> fallback) variant or assert the returned class is not null before returning it if we are sure that will be the case here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assertion added. This should never be null.

…arameter.

    Return type for Kotlin suspending functions (as returned by
    MethodParameter#getParameterType and MethodParameter#getgenericReturnType
    methods) is incorrect. The true return type is the generic parameter
    of the last parameter of the method.

    This change modifies the behaviour of the aforementioned
    methods so that they work correctly for all cases.

    Issue: SPR-16515
@sdeleuze
Copy link
Contributor

After reviewing more in detail this PR, I am not sure yet Coroutines should be managed at MethodParameter level. I was initially tempted to refactor it to manage a generalized version of what we support for Optional, partially because we have SPR-16530 which requires a more generalized support of wrapper types like Option / Try / Either / Lazy. We could for example imagine a MethodParameter#nestedIfWrapped that would unwrap these wrappers including Coroutine Continuation by reusing the logic you implemented @konrad-kaminski.

But I am not sure this is the right way to support that, because Coroutines are more high-level than just a wrapper. As described here, suspend fun <T> foo(): T becomes fun <T> foo(continuation: Continuation<T>): Any?. The type information moves from the return values to the last parameter generic nested type so IMO hardcoding a clever recognition of suspending function return type is not necessarily what we always want and could lead to some unexpected behavior.

So what are the alternatives?

Coroutines are more related to Mono than to Optional so I thought it could maybe be a good idea to use ReactiveAdapter to deal with Coroutines types but an issue with current API is that ReactiveTypeDescriptor deals with Class, not with ResolvableType which could allow us to find the potentially suspending function via ResolvableType#getSource. So one option could maybe be to update ReactiveTypeDescriptor to deal with ResolvableType instead of Class (with deprecation in 5.1 of Class based API). This could allow us to find the right return type of suspending functions. Another important pro for using ReactiveAdapter here is that it could be maybe used to implement Coroutines -> Mono conversion in a more cleanly designed way than what is done in CustomControllerMethodResolver. This could maybe be a fix for SPR-15413, reused in Spring Data, etc.

Any thoughts @jhoeller @rstoyanchev @konrad-kaminski ?

@sdeleuze sdeleuze changed the title Return correct return type for Kotlin suspending functions in MethodP… Return correct return type for Kotlin suspending functions in MethodParameter. May 17, 2018
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jan 24, 2019
@sdeleuze
Copy link
Contributor

sdeleuze commented Mar 6, 2019

Merged via this revised commit which leverages Kotlin reflection that now supports Coroutines. Thanks @konrad-kaminski for this contribution.

@sdeleuze sdeleuze closed this Mar 6, 2019
@bclozel bclozel removed the status: waiting-for-triage An issue we've not yet triaged or decided on label Feb 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants