* GH-3902: Add Kotlin Coroutines Support Fixes https://github.com/spring-projects/spring-integration/issues/3902 * Add `isAsync()` propagation from the `MessagingMethodInvokerHelper` to the `AbstractMessageProducingHandler` to set into its `async` property. The logic is based on a `CompletableFuture`, `Publisher` or Kotlin `suspend` return types of the POJO method * Introduce `IntegrationMessageHandlerMethodFactory` and `IntegrationInvocableHandlerMethod` to extend the logic to newly introduced `ContinuationHandlerMethodArgumentResolver` and call for Kotlin suspend functions. * Remove `MessageHandlerMethodFactoryCreatingFactoryBean` since its logic now is covered with the `IntegrationMessageHandlerMethodFactory` * Kotlin suspend functions are essentially reactive, so use `CoroutinesUtils.invokeSuspendingFunction()` and existing logic in the `AbstractMessageProducingHandler` to deal with `Publisher` reply * Fix `GroovySplitterTests` for the current code base * Add `kotlinx.coroutines.flow.Flow` support The `Flow` is essentially a multi-value reactive `Publisher`, so use `ReactiveAdapterRegistry` to convert any custom reactive streams result to `Flux` and `Mono` which we already support as reply types * Add docs for `Kotlin Coroutines` Rearrange the doc a bit extracting Kotlin support to individual `kotlin-functions.adoc` file * Fix missed link to `reactive-streams.adoc` from the `index-single.adoc` * Fix unintended Javadocs formatting in the `AbstractMessageProducingHandler` * Add suspend functions support for Messaging Gateway * Add convenient `CoroutinesUtils` for Coroutines types and `Continuation` argument fulfilling via `Mono` * Treat `suspend fun` in the `GatewayProxyFactoryBean` as a `Mono` return * Convert `Mono` to the `Continuation` resuming in the end of gateway call * Document `suspend fun` for `@MessagingGateway` * * Make `async` implicitly only for `suspend fun` * * Remove unused imports * * Verify sync and async `Flow` processing * Mention default sync behavior in the docs * * Improve reflection in the `CoroutinesUtils` * Fix language in docs Co-authored-by: Gary Russell <grussell@vmware.com> * * Rebase and revert blank lines around `include` in docs Co-authored-by: Gary Russell <grussell@vmware.com>
113 lines
3.4 KiB
Plaintext
113 lines
3.4 KiB
Plaintext
[[functions-support]]
|
|
=== `java.util.function` Interfaces Support
|
|
|
|
Starting with version 5.1, Spring Integration provides direct support for interfaces in the `java.util.function` package.
|
|
All messaging endpoints, (Service Activator, Transformer, Filter, etc.) can now refer to `Function` (or `Consumer`) beans.
|
|
The <<./configuration.adoc#annotations,Messaging Annotations>> can be applied directly on these beans similar to regular `MessageHandler` definitions.
|
|
For example if you have this `Function` bean definition:
|
|
|
|
|
|
====
|
|
[source, java]
|
|
----
|
|
@Configuration
|
|
public class FunctionConfiguration {
|
|
|
|
@Bean
|
|
public Function<String, String> functionAsService() {
|
|
return String::toUpperCase;
|
|
}
|
|
|
|
}
|
|
----
|
|
====
|
|
|
|
You can use it as a simple reference in an XML configuration file:
|
|
|
|
====
|
|
[source, xml]
|
|
----
|
|
<service-activator input-channel="processorViaFunctionChannel" ref="functionAsService"/>
|
|
----
|
|
====
|
|
|
|
When we configure our flow with Messaging Annotations, the code is straightforward:
|
|
|
|
====
|
|
[source, java]
|
|
----
|
|
@Bean
|
|
@Transformer(inputChannel = "functionServiceChannel")
|
|
public Function<String, String> functionAsService() {
|
|
return String::toUpperCase;
|
|
}
|
|
----
|
|
====
|
|
|
|
When the function returns an array, `Collection` (essentially, any `Iterable`), `Stream` or Reactor `Flux`, `@Splitter` can be used on such a bean to perform iteration over the result content.
|
|
|
|
The `java.util.function.Consumer` interface can be used for an `<int:outbound-channel-adapter>` or, together with the `@ServiceActivator` annotation, to perform the final step of a flow:
|
|
|
|
====
|
|
[source, java]
|
|
----
|
|
@Bean
|
|
@ServiceActivator(inputChannel = "messageConsumerServiceChannel")
|
|
public Consumer<Message<?>> messageConsumerAsService() {
|
|
// Has to be an anonymous class for proper type inference
|
|
return new Consumer<Message<?>>() {
|
|
|
|
@Override
|
|
public void accept(Message<?> e) {
|
|
collector().add(e);
|
|
}
|
|
|
|
};
|
|
}
|
|
----
|
|
====
|
|
|
|
Also, pay attention to the comment in the code snippet above: if you would like to deal with the whole message in your `Function`/`Consumer` you cannot use a lambda definition.
|
|
Because of Java type erasure we cannot determine the target type for the `apply()/accept()` method call.
|
|
|
|
The `java.util.function.Supplier` interface can simply be used together with the `@InboundChannelAdapter` annotation, or as a `ref` in an `<int:inbound-channel-adapter>`:
|
|
|
|
====
|
|
[source, java]
|
|
----
|
|
@Bean
|
|
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
|
|
public Supplier<String> pojoSupplier() {
|
|
return () -> "foo";
|
|
}
|
|
----
|
|
====
|
|
|
|
With the Java DSL we just need to use a reference to the function bean in the endpoint definitions.
|
|
Meanwhile, an implementation of the `Supplier` interface can be used as regular `MessageSource` definition:
|
|
|
|
====
|
|
[source, java]
|
|
----
|
|
@Bean
|
|
public Function<String, String> toUpperCaseFunction() {
|
|
return String::toUpperCase;
|
|
}
|
|
|
|
@Bean
|
|
public Supplier<String> stringSupplier() {
|
|
return () -> "foo";
|
|
}
|
|
|
|
@Bean
|
|
public IntegrationFlow supplierFlow() {
|
|
return IntegrationFlow.from(stringSupplier())
|
|
.transform(toUpperCaseFunction())
|
|
.channel("suppliedChannel")
|
|
.get();
|
|
}
|
|
----
|
|
====
|
|
|
|
This function support is useful when used together with the https://cloud.spring.io/spring-cloud-function/[Spring Cloud Function] framework, where we have a function catalog and can refer to its member functions from an integration flow definition.
|