Skip to content
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

Kotlin DSL: handle(handler: (P, MessageHeaders) -> Any) endpoint should not require output channel if lambda returns void #3344

Closed
ikarsokolov opened this issue Jul 16, 2020 · 5 comments · Fixed by #3346

Comments

@ikarsokolov
Copy link

ikarsokolov commented Jul 16, 2020

Expected Behavior

handle<T> { payload, headers -> .. } should work without output channel configured if lambda returns void.
Like handle { message -> .. } currently does.

Current Behavior

integrationFlow(inputChannel) {
    wireTap {
        transform(Transformers.toJson(NODE))
        handle<ObjectNode> { payload, headers ->
            logger.debug(...)
        }
    }
    ...
}

throws DestinationResolutionException: no output-channel or replyChannel header available. While

integrationFlow(inputChannel) {
    wireTap {
        transform(Transformers.toJson(NODE))
        handle { message ->
            logger.debug(...)
        }
    }
    ...
}

works as intended.

Context
Now I am using this workaround, not sure if it is the best way to go:

handle<ObjectNode> { payload, headers ->
    logger.debug(...)
}
channel(nullChannel)
@ikarsokolov ikarsokolov added status: waiting-for-triage The issue need to be evaluated and its future decided type: enhancement labels Jul 16, 2020
@artembilan
Copy link
Member

Well, since your lambda doesn't return anything (because of void logger.debug()), but that function still expect from us Any as a return, Kotlin just plays smart and build for us kotlin.Unit into the return statement which essentially becomes as a reply payload.

For now it looks like we need to treat that kotlin.Unit in our reflectional method invocation code as a void and do nothing ans we do with the void.

If there are better ideas how to make this Kotlin stuff working, I'm fully open for suggestion.

Thanks.

@artembilan
Copy link
Member

@artembilan artembilan added this to the 5.4 M2 milestone Jul 17, 2020
@artembilan artembilan added backport 5.3.x and removed status: waiting-for-triage The issue need to be evaluated and its future decided labels Jul 17, 2020
@artembilan artembilan self-assigned this Jul 17, 2020
artembilan added a commit to artembilan/spring-integration that referenced this issue Jul 17, 2020
Fixes spring-projects#3344

When function lambda doesn't return anything (e.g. a `void` method call is the last one),
Kotlin produces a `kotlin.Unit` instance as a return value which is not null and produced
as a reply message payload.

* Fix `MessagingMethodInvokerHelper` to treat a `kotlin.Unit` as `null` for reply
making Kotlin lambdas working the same way as Java lambdas when we don't return anything
from from there

**Cherry-pick to `5.3.x`**
@artembilan
Copy link
Member

See PR on the matter: #3346

@ikarsokolov
Copy link
Author

@artembilan I think you nailed it.

Another possible idea I have is to add to DSL handle(handler: (P, MessageHeaders) -> Unit) but I think this is not possible because of the type erasure and the two handle functions will be shadowed.

@artembilan
Copy link
Member

True.
I think we can live with my fix for a while.
We still need to have Java interoperability.

garyrussell pushed a commit that referenced this issue Jul 20, 2020
* GH-3344: Treat kotlin.Unit return as null in MMIH

Fixes #3344

When function lambda doesn't return anything (e.g. a `void` method call is the last one),
Kotlin produces a `kotlin.Unit` instance as a return value which is not null and produced
as a reply message payload.

* Fix `MessagingMethodInvokerHelper` to treat a `kotlin.Unit` as `null` for reply
making Kotlin lambdas working the same way as Java lambdas when we don't return anything
from from there

**Cherry-pick to `5.3.x`**

* * Introduce `ClassUtils.isKotlinUnit(Class)` API;
use it in the `MessagingMethodInvokerHelper` instead of
`.getName().equals()`

* * Fix since on new `isKotlinUnit()` API
garyrussell pushed a commit that referenced this issue Jul 20, 2020
* GH-3344: Treat kotlin.Unit return as null in MMIH

Fixes #3344

When function lambda doesn't return anything (e.g. a `void` method call is the last one),
Kotlin produces a `kotlin.Unit` instance as a return value which is not null and produced
as a reply message payload.

* Fix `MessagingMethodInvokerHelper` to treat a `kotlin.Unit` as `null` for reply
making Kotlin lambdas working the same way as Java lambdas when we don't return anything
from from there

**Cherry-pick to `5.3.x`**

* * Introduce `ClassUtils.isKotlinUnit(Class)` API;
use it in the `MessagingMethodInvokerHelper` instead of
`.getName().equals()`

* * Fix since on new `isKotlinUnit()` API
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants