Improve functions support
* Add `functions-support.adoc` chapter * Add more tests * Improve `InboundChannelAdapterAnnotationPostProcessor` to support Kotlin `Function0` * Add `FunctionsTests.kt` * Reformat Kotlin classes to use tabs * Upgrade to Kotlin `1.2.71` * Add `What's New` bullet Doc Polishing
This commit is contained in:
committed by
Gary Russell
parent
e7bc060e55
commit
7176690e4d
141
src/reference/asciidoc/functions-support.adoc
Normal file
141
src/reference/asciidoc/functions-support.adoc
Normal file
@@ -0,0 +1,141 @@
|
||||
[[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 <<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 IntegrationFlows.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.
|
||||
|
||||
[[kotlin-functions-support]]
|
||||
==== Kotlin Lambdas
|
||||
|
||||
The Framework also has been improved to support Kotlin lambdas for functions, so now you can get a gain from combination of Kotlin language and Spring Integration flow definitions:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Bean
|
||||
@Transformer(inputChannel = "functionServiceChannel")
|
||||
fun kotlinFunction(): (String) -> String {
|
||||
return { it.toUpperCase() }
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "messageConsumerServiceChannel")
|
||||
fun kotlinConsumer(): (Message<Any>) -> Unit {
|
||||
return { print(it) }
|
||||
}
|
||||
|
||||
@Bean
|
||||
@InboundChannelAdapter(value = "counterChannel",
|
||||
poller = [Poller(fixedRate = "10", maxMessagesPerPoll = "1")])
|
||||
fun kotlinSupplier(): () -> String {
|
||||
return { "baz" }
|
||||
}
|
||||
----
|
||||
====
|
||||
@@ -11,7 +11,7 @@ With a `NullChannel`, you would see only the discarded message when logging at t
|
||||
The following listing shows all the possible attributes for the `logging-channel-adapter` element:
|
||||
|
||||
====
|
||||
[source]
|
||||
[source, xml]
|
||||
----
|
||||
|
||||
<int:logging-channel-adapter
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[[messaging-endpoints-chapter]]
|
||||
== Messaging Endpoints
|
||||
|
||||
// BE SURE TO PRECEDE ALL include:: with a blank line - see https://github.com/asciidoctor/asciidoctor/issues/1297
|
||||
// BE SURE TO PRECEDE ALL include:: with a blank line - see https://asciidoctor.org/docs/user-manual/#include-partitioning
|
||||
include::./endpoint.adoc[]
|
||||
|
||||
include::./gateway.adoc[]
|
||||
@@ -17,4 +17,6 @@ include::./groovy.adoc[]
|
||||
include::./handler-advice.adoc[]
|
||||
|
||||
include::./logging-adapter.adoc[]
|
||||
// BE SURE TO PRECEDE ALL include:: with a blank line - see https://github.com/asciidoctor/asciidoctor/issues/1297
|
||||
|
||||
include::./functions-support.adoc[]
|
||||
// BE SURE TO PRECEDE ALL include:: with a blank line - see https://asciidoctor.org/docs/user-manual/#include-partitioning
|
||||
|
||||
@@ -18,6 +18,14 @@ The following components are new in 5.1:
|
||||
|
||||
See <<amqp-strict-ordering>>.
|
||||
|
||||
[[x5.1-Functions]]
|
||||
==== Improved Function Support
|
||||
|
||||
The `java.util.function` interfaces now have improved integration support in the Framework components.
|
||||
Also Kotlin lambdas now can be used for handler and source methods.
|
||||
|
||||
See <<functions-support>>.
|
||||
|
||||
[[x5.1-general]]
|
||||
=== General Changes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user