Skip to content

Commit 35f7ee7

Browse files
committed
* 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`
1 parent 68399dc commit 35f7ee7

File tree

7 files changed

+115
-20
lines changed

7 files changed

+115
-20
lines changed

spring-integration-core/src/main/java/org/springframework/integration/dsl/BaseIntegrationFlowDefinition.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,8 +783,6 @@ public <P, T> B transform(@Nullable Class<P> expectedType, GenericTransformer<P,
783783
/**
784784
* Populate a {@link MessageTransformingHandler} into the endpoint with provided {@link TransformerSpec} options.
785785
* One of the 'expression', 'ref', 'refName', 'processor' or 'function' must be provided.
786-
* @param <P> the payload type - 'transform from', or {@code Message.class}.
787-
* @param <T> the target type - 'transform to'.
788786
* @return the current {@link BaseIntegrationFlowDefinition}.
789787
* @since 6.2
790788
*/

spring-integration-core/src/main/java/org/springframework/integration/dsl/TransformerSpec.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,33 +65,67 @@ protected TransformerSpec() {
6565
super(new MessageTransformingHandler());
6666
}
6767

68+
/**
69+
* Provide an expression to use an {@link ExpressionEvaluatingTransformer} for the target handler.
70+
* @param expression the SpEL expression to use.
71+
* @return the TransformerSpec
72+
*/
6873
public TransformerSpec expression(String expression) {
6974
return expression(PARSER.parseExpression(expression));
7075
}
7176

77+
/**
78+
* Provide an expression to use an {@link ExpressionEvaluatingTransformer} for the target handler.
79+
* @param expression the SpEL expression to use.
80+
* @return the TransformerSpec
81+
*/
7282
public TransformerSpec expression(Expression expression) {
7383
assertTransformerSet();
7484
this.expression = expression;
7585
return this;
7686
}
7787

88+
/**
89+
* Provide a service to use a {@link MethodInvokingTransformer} for the target handler.
90+
* @param ref the service to call as a transformer POJO.
91+
* @return the TransformerSpec
92+
*/
7893
public TransformerSpec ref(Object ref) {
7994
assertTransformerSet();
8095
this.ref = ref;
8196
return this;
8297
}
8398

99+
/**
100+
* Provide a bean name to use a {@link MethodInvokingTransformer}
101+
* (based on {@link BeanNameMessageProcessor})for the target handler.
102+
* @param refName the bean name for service to call as a transformer POJO.
103+
* @return the TransformerSpec
104+
*/
84105
public TransformerSpec refName(String refName) {
85106
assertTransformerSet();
86107
this.refName = refName;
87108
return this;
88109
}
89110

111+
/**
112+
* Provide a service method name to call. Optional.
113+
* Use only together with {@link #ref(Object)} or {@link #refName(String)}.
114+
* @param method the service method name to call.
115+
* @return the TransformerSpec
116+
*/
90117
public TransformerSpec method(@Nullable String method) {
91118
this.method = method;
92119
return this;
93120
}
94121

122+
/**
123+
* Provide a {@link GenericTransformer} as a direct delegate for {@link MessageTransformingHandler}.
124+
* @param transformer the {@link GenericTransformer} instance to use.
125+
* @param <P> the input type.
126+
* @param <T> the output type.
127+
* @return the TransformerSpec
128+
*/
95129
public <P, T> TransformerSpec transformer(GenericTransformer<P, T> transformer) {
96130
assertTransformerSet();
97131
this.transformer = transformer;
@@ -111,6 +145,11 @@ public <P> TransformerSpec expectedType(@Nullable Class<P> expectedType) {
111145
return this;
112146
}
113147

148+
/**
149+
* Provide a {@link MessageProcessorSpec} as a factory for {@link MethodInvokingTransformer} delegate.
150+
* @param processor the {@link MessageProcessorSpec} to use.
151+
* @return the TransformerSpec
152+
*/
114153
public TransformerSpec processor(MessageProcessorSpec<?> processor) {
115154
assertTransformerSet();
116155
this.processor = processor;
@@ -180,7 +219,7 @@ else if (this.transformer != null) {
180219

181220
private Transformer wrapToTransformerIfAny() {
182221
return this.transformer instanceof Transformer ? (Transformer) this.transformer :
183-
(ClassUtils.isLambda(this.transformer.getClass())
222+
(ClassUtils.isLambda(this.transformer)
184223
? new MethodInvokingTransformer(new LambdaMessageProcessor(this.transformer, this.expectedType))
185224
: new MethodInvokingTransformer(this.transformer, ClassUtils.TRANSFORMER_TRANSFORM_METHOD));
186225
}

spring-integration-core/src/main/java/org/springframework/integration/util/ClassUtils.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.integration.util;
1818

1919
import java.lang.reflect.Method;
20+
import java.lang.reflect.Proxy;
2021
import java.util.HashMap;
2122
import java.util.Map;
2223
import java.util.Set;
@@ -223,6 +224,19 @@ public static Class<?> resolvePrimitiveType(Class<?> clazz) {
223224
return PRIMITIVE_WRAPPER_TYPE_MAP.get(clazz);
224225
}
225226

227+
/**
228+
* Check if object is Java, Kotlin or Groovy lambda.
229+
* @param candidate the {@link Object} to check.
230+
* @return true if object is a Java, Kotlin or Groovy lambda.
231+
* @since 6.2
232+
*/
233+
public static boolean isLambda(Object candidate) {
234+
Class<?> aClass = candidate.getClass();
235+
return isLambda(aClass) ||
236+
(Proxy.isProxyClass(aClass) // Groovy Closure is a Lambda in Java terms
237+
&& Proxy.getInvocationHandler(candidate).getClass().getSimpleName().equals("ConvertedClosure"));
238+
}
239+
226240
/**
227241
* Check if class is Java or Kotlin lambda.
228242
* @param aClass the {@link Class} to check.

spring-integration-file/src/test/java/org/springframework/integration/file/dsl/FileTests.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,9 @@ void pollDirectories(File... directories) {
448448
.from(Files.inboundAdapter(directory).recursive(true),
449449
e -> e.poller(p -> p.fixedDelay(1000))
450450
.id(directory.getName() + ".adapter"))
451-
.transform(Files.toStringTransformer(),
452-
e -> e.id(directory.getName() + ".transformer"))
451+
.transformWith(t -> t
452+
.transformer(Files.toStringTransformer())
453+
.id(directory.getName() + ".transformer"))
453454
.channel(this.dynamicAdaptersResult)
454455
.get();
455456
this.beanFactory.initializeBean(integrationFlow, directory.getName());

spring-integration-groovy/src/main/groovy/org/springframework/integration/groovy/dsl/GroovyIntegrationFlowDefinition.groovy

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import org.springframework.integration.dsl.ResequencerSpec
4747
import org.springframework.integration.dsl.RouterSpec
4848
import org.springframework.integration.dsl.ScatterGatherSpec
4949
import org.springframework.integration.dsl.SplitterEndpointSpec
50+
import org.springframework.integration.dsl.TransformerSpec
5051
import org.springframework.integration.dsl.WireTapSpec
5152
import org.springframework.integration.filter.MethodInvokingSelector
5253
import org.springframework.integration.handler.BridgeHandler
@@ -289,8 +290,10 @@ class GroovyIntegrationFlowDefinition {
289290
* for the SpEL {@link org.springframework.expression.Expression}.
290291
* @param expression the {@code Transformer} {@link org.springframework.expression.Expression}.
291292
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
293+
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
292294
* @see org.springframework.integration.transformer.ExpressionEvaluatingTransformer
293295
*/
296+
@Deprecated(since = '6.2', forRemoval = true)
294297
GroovyIntegrationFlowDefinition transform(
295298
String expression,
296299
@DelegatesTo(value = GenericEndpointSpec<MessageTransformingHandler>, strategy = Closure.DELEGATE_FIRST)
@@ -308,8 +311,10 @@ class GroovyIntegrationFlowDefinition {
308311
* @param service the service to use.
309312
* @param methodName the method to invoke.
310313
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
314+
* @deprecated since 6.2 in favor of {@link #transform(Closure)}
311315
* @see ExpressionEvaluatingTransformer
312316
*/
317+
@Deprecated(since = '6.2', forRemoval = true)
313318
GroovyIntegrationFlowDefinition transform(
314319
Object service, String methodName = null,
315320
@DelegatesTo(value = GenericEndpointSpec<MessageTransformingHandler>, strategy = Closure.DELEGATE_FIRST)
@@ -326,8 +331,10 @@ class GroovyIntegrationFlowDefinition {
326331
* In addition accept options for the integration endpoint using {@link GenericEndpointSpec}.
327332
* @param messageProcessorSpec the {@link MessageProcessorSpec} to use.
328333
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
334+
* @deprecated since 6.2 in favor of {@link #transform(Closure)}
329335
* @see MethodInvokingTransformer
330336
*/
337+
@Deprecated(since = '6.2', forRemoval = true)
331338
GroovyIntegrationFlowDefinition transform(
332339
MessageProcessorSpec<?> messageProcessorSpec,
333340
@DelegatesTo(value = GenericEndpointSpec<MessageTransformingHandler>, strategy = Closure.DELEGATE_FIRST)
@@ -338,6 +345,24 @@ class GroovyIntegrationFlowDefinition {
338345
this
339346
}
340347

348+
/**
349+
* Populate the {@link MessageTransformingHandler} instance for the
350+
* {@link org.springframework.integration.handler.MessageProcessor} from provided {@link MessageProcessorSpec}.
351+
* In addition accept options for the integration endpoint using {@link GenericEndpointSpec}.
352+
* @param messageProcessorSpec the {@link MessageProcessorSpec} to use.
353+
* @param transformerConfigurer the {@link Consumer} to provide integration endpoint options.
354+
* @see MethodInvokingTransformer
355+
* @since 6.2
356+
*/
357+
GroovyIntegrationFlowDefinition transform(
358+
@DelegatesTo(value = TransformerSpec, strategy = Closure.DELEGATE_FIRST)
359+
@ClosureParams(value = SimpleType.class, options = 'org.springframework.integration.dsl.TransformerSpec')
360+
Closure<?> transformerConfigurer) {
361+
362+
this.delegate.transformWith createConfigurerIfAny(transformerConfigurer)
363+
this
364+
}
365+
341366
/**
342367
* Populate the {@link MessageTransformingHandler} instance
343368
* for the provided {@code payloadType} to convert at runtime.
@@ -367,7 +392,9 @@ class GroovyIntegrationFlowDefinition {
367392
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
368393
* @param < P > the payload type - 'transform from', or {@code Message.class}.
369394
* @param < T > the target type - 'transform to'.
395+
* @deprecated since 6.2 in favor of {@link #transform(Closure)}
370396
*/
397+
@Deprecated(since = '6.2', forRemoval = true)
371398
<P, T> GroovyIntegrationFlowDefinition transform(
372399
GenericTransformer<P, T> genericTransformer,
373400
@DelegatesTo(value = GenericEndpointSpec<MessageTransformingHandler>, strategy = Closure.DELEGATE_FIRST)
@@ -389,7 +416,9 @@ class GroovyIntegrationFlowDefinition {
389416
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
390417
* @param < P > the payload type - 'transform from', or {@code Message.class}.
391418
* @param < T > the target type - 'transform to'.
419+
* @deprecated since 6.2 in favor of {@link #transform(Closure)}
392420
*/
421+
@Deprecated(since = '6.2', forRemoval = true)
393422
<P, T> GroovyIntegrationFlowDefinition transform(
394423
Class<P> expectedType,
395424
GenericTransformer<P, T> genericTransformer,
@@ -1336,7 +1365,7 @@ class GroovyIntegrationFlowDefinition {
13361365
return {
13371366
closure.delegate = it
13381367
closure.resolveStrategy = Closure.DELEGATE_FIRST
1339-
closure()
1368+
closure(it)
13401369
} as Consumer<T>
13411370
}
13421371
null

spring-integration-groovy/src/test/groovy/org/springframework/integration/groovy/dsl/test/GroovyDslTests.groovy

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 the original author or authors.
2+
* Copyright 2022-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -130,11 +130,14 @@ class GroovyDslTests {
130130
def publisher = Flux.just(2, 3).map { new GenericMessage<>(it) }
131131

132132
def integrationFlow =
133-
integrationFlow(publisher)
134-
{
135-
transform Message<Integer>, { it.payload * 2 }, { id 'foo' }
136-
channel fluxChannel
137-
}
133+
integrationFlow(publisher) {
134+
transform {
135+
it.<Message<Integer>, Integer>transformer { it.payload * 2 }
136+
expectedType Message<Integer>
137+
id 'foo'
138+
}
139+
channel fluxChannel
140+
}
138141

139142
def registration = this.integrationFlowContext.registration(integrationFlow).register()
140143

@@ -217,7 +220,7 @@ class GroovyDslTests {
217220
assert groovyTestService.result.get() == 'TEST'
218221
}
219222

220-
@Configuration
223+
@Configuration(proxyBeanMethods = false)
221224
@EnableIntegration
222225
static class Config {
223226

@@ -240,7 +243,9 @@ class GroovyDslTests {
240243
requestReplyFlow() {
241244
integrationFlow {
242245
fluxTransform { it.map { it } }
243-
transform String, { it.toUpperCase() }
246+
transform {
247+
transformer { it.toUpperCase() }
248+
}
244249
}
245250
}
246251

@@ -257,8 +262,13 @@ class GroovyDslTests {
257262
integrationFlow Function<byte[], String>,
258263
{ beanName 'functionGateway' },
259264
{
260-
transform Transformers.objectToString(), { id 'objectToStringTransformer' }
261-
transform String, { it.toUpperCase() }
265+
transform {
266+
transformer Transformers.objectToString()
267+
id 'objectToStringTransformer'
268+
}
269+
transform {
270+
transformer { it.toUpperCase() }
271+
}
262272
split Message<?>, { it.payload }
263273
split Object, { it }, { id 'splitterEndpoint' }
264274
resequence()
@@ -314,11 +324,13 @@ class GroovyDslTests {
314324
wireTap integrationFlow {
315325
channel { queue 'wireTapChannel' }
316326
}
317-
delay {
327+
delay {
318328
messageGroupId 'delayGroup'
319329
defaultDelay 100
320330
}
321-
transform String, { it.toUpperCase() }
331+
transform {
332+
transformer { it.toUpperCase() }
333+
}
322334
}
323335
}
324336

spring-integration-webflux/src/test/java/org/springframework/integration/webflux/observation/WebFluxObservationPropagationTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,9 @@ IntegrationFlow webFluxRequestReplyFlow(
212212
.payloadExpression("#requestParams.name[0]")
213213
.requestChannel(webFluxRequestChannel)
214214
.id("webFluxGateway"))
215-
.<String, String>transform(String::toLowerCase, e -> e.id("testTransformer"))
215+
.transformWith(t -> t
216+
.<String, String>transformer(String::toLowerCase)
217+
.id("testTransformer"))
216218
.get();
217219
}
218220

0 commit comments

Comments
 (0)