Skip to content

Commit 94d713a

Browse files
no-issue: Infer types in place of Class<T> on Steps interface (#1223)
* Add infer types to Step Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com> * Adjust testing Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com> --------- Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com>
1 parent bb585e9 commit 94d713a

2 files changed

Lines changed: 85 additions & 54 deletions

File tree

experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/Step.java

Lines changed: 76 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,11 @@ protected SELF self() {
4747
// ---------------------------------------------------------------------------
4848

4949
/** Queue a {@code when(predicate)} to be applied on the concrete builder. */
50-
public SELF when(Predicate<?> predicate) {
51-
postConfigurers.add(b -> ((ConditionalTaskBuilder<?>) b).when(predicate));
50+
public <T> SELF when(SerializablePredicate<T> predicate) {
51+
postConfigurers.add(
52+
b ->
53+
((ConditionalTaskBuilder<?>) b)
54+
.when(predicate, ReflectionUtils.inferInputType(predicate)));
5255
return self();
5356
}
5457

@@ -115,13 +118,16 @@ public SELF then(FlowDirectiveEnum directive) {
115118
* }</pre>
116119
*
117120
* @param <T> the task result type
118-
* @param <V> the export type (what gets forwarded to the next step)
121+
* @param <R> the export type (what gets forwarded to the next step)
119122
* @param function the transformation function
120123
* @return this step for method chaining
121124
* @see io.serverlessworkflow.fluent.func.spi.FuncTaskTransformations#exportAs(Function)
122125
*/
123-
public <T, V> SELF exportAs(Function<T, V> function) {
124-
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).exportAs(function));
126+
public <T, R> SELF exportAs(SerializableFunction<T, R> function) {
127+
postConfigurers.add(
128+
b ->
129+
((FuncTaskTransformations<?>) b)
130+
.exportAs(function, ReflectionUtils.inferInputType(function)));
125131
return self();
126132
}
127133

@@ -132,13 +138,13 @@ public <T, V> SELF exportAs(Function<T, V> function) {
132138
* <p>This variant allows you to explicitly specify the input type class for better type safety.
133139
*
134140
* @param <T> the task result type
135-
* @param <V> the export type (what gets forwarded to the next step)
141+
* @param <R> the export type (what gets forwarded to the next step)
136142
* @param function the transformation function
137143
* @param taskResultClass the class of the task result type
138144
* @return this step for method chaining
139145
* @see io.serverlessworkflow.fluent.func.spi.FuncTaskTransformations#exportAs(Function, Class)
140146
*/
141-
public <T, V> SELF exportAs(Function<T, V> function, Class<T> taskResultClass) {
147+
public <T, R> SELF exportAs(Function<T, R> function, Class<T> taskResultClass) {
142148
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).exportAs(function, taskResultClass));
143149
return self();
144150
}
@@ -150,13 +156,16 @@ public <T, V> SELF exportAs(Function<T, V> function, Class<T> taskResultClass) {
150156
* metadata when shaping the export.
151157
*
152158
* @param <T> the task result type
153-
* @param <V> the export type (what gets forwarded to the next step)
159+
* @param <R> the export type (what gets forwarded to the next step)
154160
* @param function the filter function with workflow and task context
155161
* @return this step for method chaining
156162
* @see io.serverlessworkflow.fluent.func.spi.FuncTaskTransformations#exportAs(FilterFunction)
157163
*/
158-
public <T, V> SELF exportAs(FilterFunction<T, V> function) {
159-
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).exportAs(function));
164+
public <T, R> SELF exportAs(FilterFunction<T, R> function) {
165+
postConfigurers.add(
166+
b ->
167+
((FuncTaskTransformations<?>) b)
168+
.exportAs(function, ReflectionUtils.inferInputType(function)));
160169
return self();
161170
}
162171

@@ -172,7 +181,7 @@ public <T, V> SELF exportAs(FilterFunction<T, V> function) {
172181
* @see io.serverlessworkflow.fluent.func.spi.FuncTaskTransformations#exportAs(FilterFunction,
173182
* Class)
174183
*/
175-
public <T, V> SELF exportAs(FilterFunction<T, V> function, Class<T> taskResultClass) {
184+
public <T, R> SELF exportAs(FilterFunction<T, R> function, Class<T> taskResultClass) {
176185
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).exportAs(function, taskResultClass));
177186
return self();
178187
}
@@ -184,13 +193,16 @@ public <T, V> SELF exportAs(FilterFunction<T, V> function, Class<T> taskResultCl
184193
* when shaping the export.
185194
*
186195
* @param <T> the task result type
187-
* @param <V> the export type (what gets forwarded to the next step)
196+
* @param <R> the export type (what gets forwarded to the next step)
188197
* @param function the context function with workflow context
189198
* @return this step for method chaining
190199
* @see io.serverlessworkflow.fluent.func.spi.FuncTaskTransformations#exportAs(ContextFunction)
191200
*/
192-
public <T, V> SELF exportAs(ContextFunction<T, V> function) {
193-
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).exportAs(function));
201+
public <T, R> SELF exportAs(ContextFunction<T, R> function) {
202+
postConfigurers.add(
203+
b ->
204+
((FuncTaskTransformations<?>) b)
205+
.exportAs(function, ReflectionUtils.inferInputType(function)));
194206
return self();
195207
}
196208

@@ -199,14 +211,14 @@ public <T, V> SELF exportAs(ContextFunction<T, V> function) {
199211
* explicit input type.
200212
*
201213
* @param <T> the task result type
202-
* @param <V> the export type (what gets forwarded to the next step)
214+
* @param <R> the export type (what gets forwarded to the next step)
203215
* @param function the context function with workflow context
204216
* @param taskResultClass the class of the task result type
205217
* @return this step for method chaining
206218
* @see io.serverlessworkflow.fluent.func.spi.FuncTaskTransformations#exportAs(ContextFunction,
207219
* Class)
208220
*/
209-
public <T, V> SELF exportAs(ContextFunction<T, V> function, Class<T> taskResultClass) {
221+
public <T, R> SELF exportAs(ContextFunction<T, R> function, Class<T> taskResultClass) {
210222
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).exportAs(function, taskResultClass));
211223
return self();
212224
}
@@ -253,13 +265,16 @@ public SELF exportAs(String jqExpression) {
253265
* }</pre>
254266
*
255267
* @param <T> the task result type
256-
* @param <V> the output type (what gets written to workflow data)
268+
* @param <R> the output type (what gets written to workflow data)
257269
* @param function the transformation function
258270
* @return this step for method chaining
259271
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#outputAs(Function)
260272
*/
261-
public <T, V> SELF outputAs(Function<T, V> function) {
262-
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).outputAs(function));
273+
public <T, R> SELF outputAs(SerializableFunction<T, R> function) {
274+
postConfigurers.add(
275+
b ->
276+
((FuncTaskTransformations<?>) b)
277+
.outputAs(function, ReflectionUtils.inferInputType(function)));
263278
return self();
264279
}
265280

@@ -270,13 +285,13 @@ public <T, V> SELF outputAs(Function<T, V> function) {
270285
* <p>This variant allows you to explicitly specify the input type class for better type safety.
271286
*
272287
* @param <T> the task result type
273-
* @param <V> the output type (what gets written to workflow data)
288+
* @param <R> the output type (what gets written to workflow data)
274289
* @param function the transformation function
275290
* @param taskResultClass the class of the task result type
276291
* @return this step for method chaining
277292
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#outputAs(Function, Class)
278293
*/
279-
public <T, V> SELF outputAs(Function<T, V> function, Class<T> taskResultClass) {
294+
public <T, R> SELF outputAs(Function<T, R> function, Class<T> taskResultClass) {
280295
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).outputAs(function, taskResultClass));
281296
return self();
282297
}
@@ -306,13 +321,16 @@ public <T, V> SELF outputAs(Function<T, V> function, Class<T> taskResultClass) {
306321
* }</pre>
307322
*
308323
* @param <T> the task result type
309-
* @param <V> the output type (what gets written to workflow data)
324+
* @param <R> the output type (what gets written to workflow data)
310325
* @param function the filter function with workflow and task context
311326
* @return this step for method chaining
312327
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#outputAs(FilterFunction)
313328
*/
314-
public <T, V> SELF outputAs(FilterFunction<T, V> function) {
315-
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).outputAs(function));
329+
public <T, R> SELF outputAs(FilterFunction<T, R> function) {
330+
postConfigurers.add(
331+
b ->
332+
((FuncTaskTransformations<?>) b)
333+
.outputAs(function, ReflectionUtils.inferInputType(function)));
316334
return self();
317335
}
318336

@@ -321,13 +339,13 @@ public <T, V> SELF outputAs(FilterFunction<T, V> function) {
321339
* function with explicit input type.
322340
*
323341
* @param <T> the task result type
324-
* @param <V> the output type (what gets written to workflow data)
342+
* @param <R> the output type (what gets written to workflow data)
325343
* @param function the filter function with workflow and task context
326344
* @param taskResultClass the class of the task result type
327345
* @return this step for method chaining
328346
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#outputAs(FilterFunction, Class)
329347
*/
330-
public <T, V> SELF outputAs(FilterFunction<T, V> function, Class<T> taskResultClass) {
348+
public <T, R> SELF outputAs(FilterFunction<T, R> function, Class<T> taskResultClass) {
331349
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).outputAs(function, taskResultClass));
332350
return self();
333351
}
@@ -339,13 +357,16 @@ public <T, V> SELF outputAs(FilterFunction<T, V> function, Class<T> taskResultCl
339357
* when shaping the committed output.
340358
*
341359
* @param <T> the task result type
342-
* @param <V> the output type (what gets written to workflow data)
360+
* @param <R> the output type (what gets written to workflow data)
343361
* @param function the context function with workflow context
344362
* @return this step for method chaining
345363
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#outputAs(ContextFunction)
346364
*/
347-
public <T, V> SELF outputAs(ContextFunction<T, V> function) {
348-
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).outputAs(function));
365+
public <T, R> SELF outputAs(ContextFunction<T, R> function) {
366+
postConfigurers.add(
367+
b ->
368+
((FuncTaskTransformations<?>) b)
369+
.outputAs(function, ReflectionUtils.inferInputType(function)));
349370
return self();
350371
}
351372

@@ -354,13 +375,13 @@ public <T, V> SELF outputAs(ContextFunction<T, V> function) {
354375
* with explicit input type.
355376
*
356377
* @param <T> the task result type
357-
* @param <V> the output type (what gets written to workflow data)
378+
* @param <R> the output type (what gets written to workflow data)
358379
* @param function the context function with workflow context
359380
* @param taskResultClass the class of the task result type
360381
* @return this step for method chaining
361382
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#outputAs(ContextFunction, Class)
362383
*/
363-
public <T, V> SELF outputAs(ContextFunction<T, V> function, Class<T> taskResultClass) {
384+
public <T, R> SELF outputAs(ContextFunction<T, R> function, Class<T> taskResultClass) {
364385
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).outputAs(function, taskResultClass));
365386
return self();
366387
}
@@ -406,13 +427,16 @@ public SELF outputAs(String jqExpression) {
406427
* }</pre>
407428
*
408429
* @param <T> the input type (workflow data or task input)
409-
* @param <V> the result type (what the task will see as input)
430+
* @param <R> the result type (what the task will see as input)
410431
* @param function the transformation function
411432
* @return this step for method chaining
412433
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#inputFrom(Function)
413434
*/
414-
public <T, V> SELF inputFrom(Function<T, V> function) {
415-
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).inputFrom(function));
435+
public <T, R> SELF inputFrom(SerializableFunction<T, R> function) {
436+
postConfigurers.add(
437+
b ->
438+
((FuncTaskTransformations<?>) b)
439+
.inputFrom(function, ReflectionUtils.inferInputType(function)));
416440
return self();
417441
}
418442

@@ -430,13 +454,13 @@ public <T, V> SELF inputFrom(Function<T, V> function) {
430454
* }</pre>
431455
*
432456
* @param <T> the input type (workflow data or task input)
433-
* @param <V> the result type (what the task will see as input)
457+
* @param <R> the result type (what the task will see as input)
434458
* @param function the transformation function
435459
* @param inputClass the class of the input type
436460
* @return this step for method chaining
437461
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#inputFrom(Function, Class)
438462
*/
439-
public <T, V> SELF inputFrom(Function<T, V> function, Class<T> inputClass) {
463+
public <T, R> SELF inputFrom(Function<T, R> function, Class<T> inputClass) {
440464
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).inputFrom(function, inputClass));
441465
return self();
442466
}
@@ -462,13 +486,16 @@ public <T, V> SELF inputFrom(Function<T, V> function, Class<T> inputClass) {
462486
* }</pre>
463487
*
464488
* @param <T> the input type (workflow data or task input)
465-
* @param <V> the result type (what the task will see as input)
489+
* @param <R> the result type (what the task will see as input)
466490
* @param function the filter function with workflow and task context
467491
* @return this step for method chaining
468492
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#inputFrom(FilterFunction)
469493
*/
470-
public <T, V> SELF inputFrom(FilterFunction<T, V> function) {
471-
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).inputFrom(function));
494+
public <T, R> SELF inputFrom(FilterFunction<T, R> function) {
495+
postConfigurers.add(
496+
b ->
497+
((FuncTaskTransformations<?>) b)
498+
.inputFrom(function, ReflectionUtils.inferInputType(function)));
472499
return self();
473500
}
474501

@@ -479,13 +506,13 @@ public <T, V> SELF inputFrom(FilterFunction<T, V> function) {
479506
* specification.
480507
*
481508
* @param <T> the input type (workflow data or task input)
482-
* @param <V> the result type (what the task will see as input)
509+
* @param <R> the result type (what the task will see as input)
483510
* @param function the filter function with workflow and task context
484511
* @param inputClass the class of the input type
485512
* @return this step for method chaining
486513
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#inputFrom(FilterFunction, Class)
487514
*/
488-
public <T, V> SELF inputFrom(FilterFunction<T, V> function, Class<T> inputClass) {
515+
public <T, R> SELF inputFrom(FilterFunction<T, R> function, Class<T> inputClass) {
489516
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).inputFrom(function, inputClass));
490517
return self();
491518
}
@@ -497,13 +524,16 @@ public <T, V> SELF inputFrom(FilterFunction<T, V> function, Class<T> inputClass)
497524
* you to inspect workflow metadata and current data.
498525
*
499526
* @param <T> the input type (workflow data or task input)
500-
* @param <V> the result type (what the task will see as input)
527+
* @param <R> the result type (what the task will see as input)
501528
* @param function the context function with workflow context
502529
* @return this step for method chaining
503530
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#inputFrom(ContextFunction)
504531
*/
505-
public <T, V> SELF inputFrom(ContextFunction<T, V> function) {
506-
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).inputFrom(function));
532+
public <T, R> SELF inputFrom(ContextFunction<T, R> function) {
533+
postConfigurers.add(
534+
b ->
535+
((FuncTaskTransformations<?>) b)
536+
.inputFrom(function, ReflectionUtils.inferInputType(function)));
507537
return self();
508538
}
509539

@@ -514,14 +544,14 @@ public <T, V> SELF inputFrom(ContextFunction<T, V> function) {
514544
* specification.
515545
*
516546
* @param <T> the input type (workflow data or task input)
517-
* @param <V> the result type (what the task will see as input)
547+
* @param <R> the result type (what the task will see as input)
518548
* @param function the context function with workflow context
519549
* @param inputClass the class of the input type
520550
* @return this step for method chaining
521551
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#inputFrom(ContextFunction,
522552
* Class)
523553
*/
524-
public <T, V> SELF inputFrom(ContextFunction<T, V> function, Class<T> inputClass) {
554+
public <T, R> SELF inputFrom(ContextFunction<T, R> function, Class<T> inputClass) {
525555
postConfigurers.add(b -> ((FuncTaskTransformations<?>) b).inputFrom(function, inputClass));
526556
return self();
527557
}

experimental/lambda/src/test/java/io/serverless/workflow/impl/executors/func/FuncDSLDataFlowTransformationHelpersTest.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121

2222
import io.serverlessworkflow.api.types.Workflow;
2323
import io.serverlessworkflow.fluent.func.FuncWorkflowBuilder;
24+
import io.serverlessworkflow.impl.TaskContextData;
2425
import io.serverlessworkflow.impl.WorkflowApplication;
26+
import io.serverlessworkflow.impl.WorkflowContextData;
2527
import io.serverlessworkflow.impl.WorkflowDefinition;
2628
import io.serverlessworkflow.impl.WorkflowModel;
2729
import org.assertj.core.api.SoftAssertions;
@@ -42,17 +44,15 @@ void test_input_with_inputFrom() {
4244
(Long input) -> {
4345
softly.assertThat(input).isEqualTo(10L);
4446
return input + 5;
45-
},
46-
Long.class),
47+
}),
4748
function("returnEnriched", (Long enrichedValue) -> enrichedValue, Long.class)
4849
.inputFrom(
49-
(object, workflowContext) -> {
50+
(Long object, WorkflowContextData workflowContext) -> {
5051
softly.assertThat(object).isEqualTo(15L);
5152
Long input = input(workflowContext, Long.class);
5253
softly.assertThat(input).isEqualTo(10L);
5354
return object + input;
54-
},
55-
Long.class))
55+
}))
5656
.build();
5757

5858
try (WorkflowApplication app = WorkflowApplication.builder().build()) {
@@ -118,12 +118,13 @@ void test_output_with_exportAs() {
118118
},
119119
Long.class)
120120
.exportAs(
121-
(object, workflowContext, taskContextData) -> {
121+
(Long object,
122+
WorkflowContextData workflowContext,
123+
TaskContextData taskContextData) -> {
122124
Long taskOutput = output(taskContextData, Long.class);
123125
softly.assertThat(taskOutput).isEqualTo(15L);
124126
return taskOutput * 2;
125-
},
126-
Object.class))
127+
}))
127128
.build();
128129

129130
try (WorkflowApplication app = WorkflowApplication.builder().build()) {

0 commit comments

Comments
 (0)