GH-8626: Provide cleaner transform() DSL (#8653)

* GH-8626: Provide cleaner `transform()` DSL

Fixes https://github.com/spring-projects/spring-integration/issues/8626

* Add missed `transform(String beanName, @Nullable String methodName)` API
* Introduce a `TransformerSpec` to expose a strict API to configure
transformer variants.
* Introduce `transformWith(Consumer<TransformerSpec>)` as a single point
of all possible transformer and its endpoint options
* Deprecate those `IntegrationFlowDefinition.transform()` variants
which are harder to configure as several lambda arguments

This change will make Kotlin & Groovy DSL more readable and straightforward

* * Use new `transformWith()` in tests where a deprecated API still used
* Add JavaDocs to `TransformerSpec`
* Fix generic types for `BaseIntegrationFlowDefinition.transformWith()` -
they make sense exactly on the `TransformerSpec.transformer()` only
* Apply `transformWith()` for Groovy DSL
* Introduce a new `ClassUtils.isLambda(Object candidate)`
and add a check for Groovy `Closure`
* Fix `GroovyIntegrationFlowDefinition.createConfigurerIfAny()` to propagate a `Consumer` argument
down to the `Closure`

* * Rename `TransformerSpec -> TransformerEndpointSpec` for better context
meaning of the class
* Introduce `KotlinTransformerEndpointSpec` as an extension of the `TransformerEndpointSpec`
to have an `inline fun <reified P> transformer(crossinline function: (P) -> Any)`
for Kotlin style
* Add `KotlinIntegrationFlowDefinition.transformWith(KotlinTransformerEndpointSpec)`
* Deprecate Kotlin methods which are covered by the mentioned `transformWith()`
* Fix tests to use new API
* Mentioned the change in the doc
This commit is contained in:
Artem Bilan
2023-06-26 12:01:13 -04:00
committed by GitHub
parent ceb3daec8e
commit 070c1c6e60
20 changed files with 593 additions and 61 deletions

View File

@@ -47,6 +47,7 @@ import org.springframework.integration.dsl.ResequencerSpec
import org.springframework.integration.dsl.RouterSpec
import org.springframework.integration.dsl.ScatterGatherSpec
import org.springframework.integration.dsl.SplitterEndpointSpec
import org.springframework.integration.dsl.TransformerEndpointSpec
import org.springframework.integration.dsl.WireTapSpec
import org.springframework.integration.filter.MethodInvokingSelector
import org.springframework.integration.handler.BridgeHandler
@@ -289,8 +290,10 @@ class GroovyIntegrationFlowDefinition {
* for the SpEL {@link org.springframework.expression.Expression}.
* @param expression the {@code Transformer} {@link org.springframework.expression.Expression}.
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
* @see org.springframework.integration.transformer.ExpressionEvaluatingTransformer
*/
@Deprecated(since = '6.2', forRemoval = true)
GroovyIntegrationFlowDefinition transform(
String expression,
@DelegatesTo(value = GenericEndpointSpec<MessageTransformingHandler>, strategy = Closure.DELEGATE_FIRST)
@@ -308,8 +311,10 @@ class GroovyIntegrationFlowDefinition {
* @param service the service to use.
* @param methodName the method to invoke.
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
* @deprecated since 6.2 in favor of {@link #transform(Closure)}
* @see ExpressionEvaluatingTransformer
*/
@Deprecated(since = '6.2', forRemoval = true)
GroovyIntegrationFlowDefinition transform(
Object service, String methodName = null,
@DelegatesTo(value = GenericEndpointSpec<MessageTransformingHandler>, strategy = Closure.DELEGATE_FIRST)
@@ -326,8 +331,10 @@ class GroovyIntegrationFlowDefinition {
* In addition accept options for the integration endpoint using {@link GenericEndpointSpec}.
* @param messageProcessorSpec the {@link MessageProcessorSpec} to use.
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
* @deprecated since 6.2 in favor of {@link #transform(Closure)}
* @see MethodInvokingTransformer
*/
@Deprecated(since = '6.2', forRemoval = true)
GroovyIntegrationFlowDefinition transform(
MessageProcessorSpec<?> messageProcessorSpec,
@DelegatesTo(value = GenericEndpointSpec<MessageTransformingHandler>, strategy = Closure.DELEGATE_FIRST)
@@ -338,6 +345,24 @@ class GroovyIntegrationFlowDefinition {
this
}
/**
* Populate the {@link MessageTransformingHandler} instance for the
* {@link org.springframework.integration.handler.MessageProcessor} from provided {@link MessageProcessorSpec}.
* In addition accept options for the integration endpoint using {@link GenericEndpointSpec}.
* @param messageProcessorSpec the {@link MessageProcessorSpec} to use.
* @param transformerConfigurer the {@link Consumer} to provide integration endpoint options.
* @see MethodInvokingTransformer
* @since 6.2
*/
GroovyIntegrationFlowDefinition transform(
@DelegatesTo(value = TransformerEndpointSpec, strategy = Closure.DELEGATE_FIRST)
@ClosureParams(value = SimpleType.class, options = 'org.springframework.integration.dsl.TransformerEndpointSpec')
Closure<?> transformerConfigurer) {
this.delegate.transformWith createConfigurerIfAny(transformerConfigurer)
this
}
/**
* Populate the {@link MessageTransformingHandler} instance
* for the provided {@code payloadType} to convert at runtime.
@@ -367,7 +392,9 @@ class GroovyIntegrationFlowDefinition {
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
* @param < P > the payload type - 'transform from', or {@code Message.class}.
* @param < T > the target type - 'transform to'.
* @deprecated since 6.2 in favor of {@link #transform(Closure)}
*/
@Deprecated(since = '6.2', forRemoval = true)
<P, T> GroovyIntegrationFlowDefinition transform(
GenericTransformer<P, T> genericTransformer,
@DelegatesTo(value = GenericEndpointSpec<MessageTransformingHandler>, strategy = Closure.DELEGATE_FIRST)
@@ -389,7 +416,9 @@ class GroovyIntegrationFlowDefinition {
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
* @param < P > the payload type - 'transform from', or {@code Message.class}.
* @param < T > the target type - 'transform to'.
* @deprecated since 6.2 in favor of {@link #transform(Closure)}
*/
@Deprecated(since = '6.2', forRemoval = true)
<P, T> GroovyIntegrationFlowDefinition transform(
Class<P> expectedType,
GenericTransformer<P, T> genericTransformer,
@@ -1336,7 +1365,7 @@ class GroovyIntegrationFlowDefinition {
return {
closure.delegate = it
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure()
closure(it)
} as Consumer<T>
}
null

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2022 the original author or authors.
* Copyright 2022-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -130,11 +130,14 @@ class GroovyDslTests {
def publisher = Flux.just(2, 3).map { new GenericMessage<>(it) }
def integrationFlow =
integrationFlow(publisher)
{
transform Message<Integer>, { it.payload * 2 }, { id 'foo' }
channel fluxChannel
}
integrationFlow(publisher) {
transform {
it.<Message<Integer>, Integer>transformer { it.payload * 2 }
expectedType Message<Integer>
id 'foo'
}
channel fluxChannel
}
def registration = this.integrationFlowContext.registration(integrationFlow).register()
@@ -217,7 +220,7 @@ class GroovyDslTests {
assert groovyTestService.result.get() == 'TEST'
}
@Configuration
@Configuration(proxyBeanMethods = false)
@EnableIntegration
static class Config {
@@ -240,7 +243,9 @@ class GroovyDslTests {
requestReplyFlow() {
integrationFlow {
fluxTransform { it.map { it } }
transform String, { it.toUpperCase() }
transform {
transformer { it.toUpperCase() }
}
}
}
@@ -257,8 +262,13 @@ class GroovyDslTests {
integrationFlow Function<byte[], String>,
{ beanName 'functionGateway' },
{
transform Transformers.objectToString(), { id 'objectToStringTransformer' }
transform String, { it.toUpperCase() }
transform {
transformer Transformers.objectToString()
id 'objectToStringTransformer'
}
transform {
transformer { it.toUpperCase() }
}
split Message<?>, { it.payload }
split Object, { it }, { id 'splitterEndpoint' }
resequence()
@@ -314,11 +324,13 @@ class GroovyDslTests {
wireTap integrationFlow {
channel { queue 'wireTapChannel' }
}
delay {
delay {
messageGroupId 'delayGroup'
defaultDelay 100
}
transform String, { it.toUpperCase() }
transform {
transformer { it.toUpperCase() }
}
}
}