Skip to content

Commit d0f6d71

Browse files
no-issue: Adding overloads to remove Class<T> param (serverlessworkflow#1219)
* no-issue: Adding overloads to remove Class<T> param Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com> * Refactor to consider biFunctions Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com> * Fix InstanceId to became a synthetic biFunction Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com> * Remove comment Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com> --------- Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com>
1 parent 1c63857 commit d0f6d71

15 files changed

Lines changed: 445 additions & 105 deletions

File tree

experimental/fluent/func/pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
34
<modelVersion>4.0.0</modelVersion>
45
<parent>
56
<groupId>io.serverlessworkflow</groupId>

experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/internal/CommonFuncOps.java renamed to experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/CommonFuncOps.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package io.serverlessworkflow.fluent.func.dsl.internal;
16+
package io.serverlessworkflow.fluent.func.dsl;
1717

1818
import io.cloudevents.CloudEventData;
1919
import io.serverlessworkflow.api.types.FlowDirectiveEnum;
@@ -22,19 +22,17 @@
2222
import io.serverlessworkflow.fluent.func.FuncSwitchTaskBuilder;
2323
import io.serverlessworkflow.fluent.func.configurers.FuncPredicateEventConfigurer;
2424
import io.serverlessworkflow.fluent.func.configurers.SwitchCaseConfigurer;
25-
import io.serverlessworkflow.fluent.func.dsl.ReflectionUtils;
26-
import io.serverlessworkflow.fluent.func.dsl.SwitchCaseSpec;
2725
import java.util.function.Consumer;
2826
import java.util.function.Function;
2927
import java.util.function.Predicate;
3028

31-
public interface CommonFuncOps {
29+
interface CommonFuncOps {
3230

3331
default <T, V> Consumer<FuncCallTaskBuilder> fn(Function<T, V> function, Class<T> argClass) {
3432
return f -> f.function(function, argClass);
3533
}
3634

37-
default <T, V> Consumer<FuncCallTaskBuilder> fn(Function<T, V> function) {
35+
default <T, V> Consumer<FuncCallTaskBuilder> fn(SerializableFunction<T, V> function) {
3836
Class<T> clazz = ReflectionUtils.inferInputType(function);
3937
return f -> f.function(function, clazz);
4038
}
@@ -51,8 +49,8 @@ default <T> SwitchCaseSpec<T> caseOf(Predicate<T> when, Class<T> whenClass) {
5149
return new SwitchCaseSpec<T>().when(when, whenClass);
5250
}
5351

54-
default <T> SwitchCaseSpec<T> caseOf(Predicate<T> when) {
55-
return new SwitchCaseSpec<T>().when(when);
52+
default <T> SwitchCaseSpec<T> caseOf(SerializablePredicate<T> when) {
53+
return new SwitchCaseSpec<T>().when(when, ReflectionUtils.inferInputType(when));
5654
}
5755

5856
default SwitchCaseConfigurer caseDefault(String task) {

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

Lines changed: 106 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import io.serverlessworkflow.fluent.func.configurers.FuncPredicateEventConfigurer;
2929
import io.serverlessworkflow.fluent.func.configurers.FuncTaskConfigurer;
3030
import io.serverlessworkflow.fluent.func.configurers.SwitchCaseConfigurer;
31-
import io.serverlessworkflow.fluent.func.dsl.internal.CommonFuncOps;
3231
import io.serverlessworkflow.fluent.spec.configurers.AuthenticationConfigurer;
3332
import io.serverlessworkflow.impl.TaskContextData;
3433
import io.serverlessworkflow.impl.WorkflowContextData;
@@ -97,15 +96,15 @@ public static <T, V> Consumer<FuncCallTaskBuilder> fn(
9796
* @param <V> output type
9897
* @return a consumer that configures a {@code FuncCallTaskBuilder}
9998
*/
100-
public static <T, V> Consumer<FuncCallTaskBuilder> fn(Function<T, V> function) {
101-
return f -> f.function(function);
99+
public static <T, V> Consumer<FuncCallTaskBuilder> fn(SerializableFunction<T, V> function) {
100+
return f -> f.function(function, ReflectionUtils.inferInputType(function));
102101
}
103102

104103
/**
105104
* Compose multiple switch cases into a single configurer for {@link FuncSwitchTaskBuilder}.
106105
*
107-
* @param cases one or more {@link SwitchCaseConfigurer} built via {@link #caseOf(Predicate)} or
108-
* {@link #caseDefault(String)}
106+
* @param cases one or more {@link SwitchCaseConfigurer} built via {@link
107+
* #caseOf(SerializablePredicate)} or {@link #caseDefault(String)}
109108
* @return a consumer to apply on a switch task builder
110109
*/
111110
public static Consumer<FuncSwitchTaskBuilder> cases(SwitchCaseConfigurer... cases) {
@@ -131,7 +130,7 @@ public static <T> SwitchCaseSpec<T> caseOf(Predicate<T> when, Class<T> whenClass
131130
* @param <T> predicate input type
132131
* @return a fluent builder to set the consequent action (e.g., {@code then("taskName")})
133132
*/
134-
public static <T> SwitchCaseSpec<T> caseOf(Predicate<T> when) {
133+
public static <T> SwitchCaseSpec<T> caseOf(SerializablePredicate<T> when) {
135134
return OPS.caseOf(when);
136135
}
137136

@@ -213,12 +212,13 @@ public static FuncListenSpec toAny(String... types) {
213212
* @return a consumer to configure {@link FuncEmitTaskBuilder}
214213
*/
215214
public static <T> Consumer<FuncEmitTaskBuilder> event(
216-
String type, Function<T, CloudEventData> function) {
217-
return OPS.event(type, function);
215+
String type, SerializableFunction<T, CloudEventData> function) {
216+
return OPS.event(type, function, ReflectionUtils.inferInputType(function));
218217
}
219218

220219
/**
221-
* Same as {@link #event(String, Function)} but with an explicit input class to guide conversion.
220+
* Same as {@link #event(String, SerializableFunction)} but with an explicit input class to guide
221+
* conversion.
222222
*
223223
* @param type CloudEvent type
224224
* @param function function that maps workflow input to {@link CloudEventData}
@@ -279,20 +279,6 @@ public static FuncPredicateEventConfigurer event(String type) {
279279
return OPS.event(type);
280280
}
281281

282-
/**
283-
* Create a {@link FuncCallStep} that calls a simple Java {@link Function} with explicit input
284-
* type.
285-
*
286-
* @param fn the function to execute at runtime
287-
* @param inputClass expected input class for model conversion
288-
* @param <T> input type
289-
* @param <R> result type
290-
* @return a call step which supports chaining (e.g., {@code .exportAs(...).when(...)})
291-
*/
292-
public static <T, R> FuncCallStep<T, R> function(Function<T, R> fn, Class<T> inputClass) {
293-
return new FuncCallStep<>(fn, inputClass);
294-
}
295-
296282
/**
297283
* Build a call step for functions that need {@link WorkflowContextData} as the first parameter.
298284
* The DSL wraps it as a {@link JavaContextFunction} and injects the runtime context.
@@ -309,21 +295,8 @@ public static <T, R> FuncCallStep<T, R> withContext(JavaContextFunction<T, R> fn
309295
return withContext(null, fn, in);
310296
}
311297

312-
/**
313-
* Build a call step for functions that expect the workflow instance ID as the first parameter.
314-
* The instance ID is extracted from the runtime context.
315-
*
316-
* <p>Signature expected: {@code (instanceId, payload) -> result}
317-
*
318-
* @param fn instance-id-aware function
319-
* @param in payload input class
320-
* @param <T> input type
321-
* @param <R> result type
322-
* @return a call step
323-
*/
324-
public static <T, R> FuncCallStep<T, R> withInstanceId(
325-
InstanceIdBiFunction<T, R> fn, Class<T> in) {
326-
return withInstanceId(null, fn, in);
298+
public static <T, R> FuncCallStep<T, R> withContext(JavaContextFunction<T, R> fn) {
299+
return withContext(null, fn, ReflectionUtils.inferInputType(fn));
327300
}
328301

329302
/**
@@ -341,6 +314,10 @@ public static <T, R> FuncCallStep<T, R> withContext(
341314
return new FuncCallStep<>(name, fn, in);
342315
}
343316

317+
public static <T, R> FuncCallStep<T, R> withContext(String name, JavaContextFunction<T, R> fn) {
318+
return new FuncCallStep<>(name, fn, ReflectionUtils.inferInputType(fn));
319+
}
320+
344321
/**
345322
* Build a call step for functions that need {@link WorkflowContextData} and {@link
346323
* TaskContextData} as the first and second parameter. The DSL wraps it as a {@link
@@ -373,8 +350,16 @@ public static <T, R> FuncCallStep<T, R> withFilter(
373350
return new FuncCallStep<>(name, fn, in);
374351
}
375352

353+
public static <T, R> FuncCallStep<T, R> withFilter(JavaFilterFunction<T, R> fn) {
354+
return withFilter(null, fn, ReflectionUtils.inferInputType(fn));
355+
}
356+
357+
public static <T, R> FuncCallStep<T, R> withFilter(String name, JavaFilterFunction<T, R> fn) {
358+
return withFilter(name, fn, ReflectionUtils.inferInputType(fn));
359+
}
360+
376361
/**
377-
* Named variant of {@link #withInstanceId(InstanceIdBiFunction, Class)}.
362+
* Named variant of {@link #withInstanceId(InstanceIdFunction, Class)}.
378363
*
379364
* @param name task name
380365
* @param fn instance-id-aware function
@@ -384,11 +369,35 @@ public static <T, R> FuncCallStep<T, R> withFilter(
384369
* @return a named call step
385370
*/
386371
public static <T, R> FuncCallStep<T, R> withInstanceId(
387-
String name, InstanceIdBiFunction<T, R> fn, Class<T> in) {
372+
String name, InstanceIdFunction<T, R> fn, Class<T> in) {
388373
JavaContextFunction<T, R> jcf = (payload, wctx) -> fn.apply(wctx.instanceData().id(), payload);
389374
return new FuncCallStep<>(name, jcf, in);
390375
}
391376

377+
/**
378+
* Build a call step for functions that expect the workflow instance ID as the first parameter.
379+
* The instance ID is extracted from the runtime context.
380+
*
381+
* <p>Signature expected: {@code (instanceId, payload) -> result}
382+
*
383+
* @param fn instance-id-aware function
384+
* @param in payload input class
385+
* @param <T> input type
386+
* @param <R> result type
387+
* @return a call step
388+
*/
389+
public static <T, R> FuncCallStep<T, R> withInstanceId(InstanceIdFunction<T, R> fn, Class<T> in) {
390+
return withInstanceId(null, fn, in);
391+
}
392+
393+
public static <T, R> FuncCallStep<T, R> withInstanceId(String name, InstanceIdFunction<T, R> fn) {
394+
return withInstanceId(name, fn, ReflectionUtils.inferInputType(fn));
395+
}
396+
397+
public static <T, R> FuncCallStep<T, R> withInstanceId(InstanceIdFunction<T, R> fn) {
398+
return withInstanceId(null, fn, ReflectionUtils.inferInputType(fn));
399+
}
400+
392401
/**
393402
* Builds a composition of the current workflow instance id and the definition of the task
394403
* position as a JSON pointer, used as a stable "unique id" for the task.
@@ -422,6 +431,10 @@ public static <T, R> FuncCallStep<T, R> withUniqueId(
422431
return new FuncCallStep<>(name, jff, in);
423432
}
424433

434+
public static <T, R> FuncCallStep<T, R> withUniqueId(String name, UniqueIdBiFunction<T, R> fn) {
435+
return withUniqueId(name, fn, ReflectionUtils.inferInputType(fn));
436+
}
437+
425438
/**
426439
* Variant of {@link #withUniqueId(String, UniqueIdBiFunction, Class)} without an explicit task
427440
* name.
@@ -436,6 +449,10 @@ public static <T, R> FuncCallStep<T, R> withUniqueId(UniqueIdBiFunction<T, R> fn
436449
return withUniqueId(null, fn, in);
437450
}
438451

452+
public static <T, R> FuncCallStep<T, R> withUniqueId(UniqueIdBiFunction<T, R> fn) {
453+
return withUniqueId(null, fn, ReflectionUtils.inferInputType(fn));
454+
}
455+
439456
/**
440457
* Create a fire-and-forget side-effect step (unnamed). The consumer receives the typed input.
441458
*
@@ -449,6 +466,10 @@ public static <T> ConsumeStep<T> consume(Consumer<T> consumer, Class<T> inputCla
449466
return new ConsumeStep<>(consumer, inputClass);
450467
}
451468

469+
public static <T> ConsumeStep<T> consume(SerializableConsumer<T> consumer) {
470+
return consume(consumer, ReflectionUtils.inferInputType(consumer));
471+
}
472+
452473
/**
453474
* Named variant of {@link #consume(Consumer, Class)}.
454475
*
@@ -462,6 +483,10 @@ public static <T> ConsumeStep<T> consume(String name, Consumer<T> consumer, Clas
462483
return new ConsumeStep<>(name, consumer, inputClass);
463484
}
464485

486+
public static <T> ConsumeStep<T> consume(String name, SerializableConsumer<T> consumer) {
487+
return consume(name, consumer, ReflectionUtils.inferInputType(consumer));
488+
}
489+
465490
/**
466491
* Agent-style sugar for methods that receive a "memory id" as first parameter. The DSL uses a
467492
* derived unique id composed of the workflow instance id and the task position (JSON pointer),
@@ -479,6 +504,10 @@ public static <T, R> FuncCallStep<T, R> agent(UniqueIdBiFunction<T, R> fn, Class
479504
return withUniqueId(fn, in);
480505
}
481506

507+
public static <T, R> FuncCallStep<T, R> agent(UniqueIdBiFunction<T, R> fn) {
508+
return withUniqueId(fn, ReflectionUtils.inferInputType(fn));
509+
}
510+
482511
/**
483512
* Named agent-style sugar. See {@link #agent(UniqueIdBiFunction, Class)}.
484513
*
@@ -496,6 +525,24 @@ public static <T, R> FuncCallStep<T, R> agent(
496525
return withUniqueId(name, fn, in);
497526
}
498527

528+
public static <T, R> FuncCallStep<T, R> agent(String name, UniqueIdBiFunction<T, R> fn) {
529+
return withUniqueId(name, fn, ReflectionUtils.inferInputType(fn));
530+
}
531+
532+
/**
533+
* Create a {@link FuncCallStep} that calls a simple Java {@link Function} with explicit input
534+
* type.
535+
*
536+
* @param fn the function to execute at runtime
537+
* @param inputClass expected input class for model conversion
538+
* @param <T> input type
539+
* @param <R> result type
540+
* @return a call step which supports chaining (e.g., {@code .exportAs(...).when(...)})
541+
*/
542+
public static <T, R> FuncCallStep<T, R> function(Function<T, R> fn, Class<T> inputClass) {
543+
return new FuncCallStep<>(fn, inputClass);
544+
}
545+
499546
/**
500547
* Create a {@link FuncCallStep} that invokes a plain Java {@link Function} with inferred input
501548
* type.
@@ -505,21 +552,21 @@ public static <T, R> FuncCallStep<T, R> agent(
505552
* @param <R> output type
506553
* @return a call step
507554
*/
508-
public static <T, R> FuncCallStep<T, R> function(Function<T, R> fn) {
555+
public static <T, R> FuncCallStep<T, R> function(SerializableFunction<T, R> fn) {
509556
Class<T> inputClass = ReflectionUtils.inferInputType(fn);
510557
return new FuncCallStep<>(fn, inputClass);
511558
}
512559

513560
/**
514-
* Named variant of {@link #function(Function)} with inferred input type.
561+
* Named variant of {@link #function(SerializableFunction)} with inferred input type.
515562
*
516563
* @param name task name
517564
* @param fn the function to execute
518565
* @param <T> input type
519566
* @param <R> output type
520567
* @return a named call step
521568
*/
522-
public static <T, R> FuncCallStep<T, R> function(String name, Function<T, R> fn) {
569+
public static <T, R> FuncCallStep<T, R> function(String name, SerializableFunction<T, R> fn) {
523570
Class<T> inputClass = ReflectionUtils.inferInputType(fn);
524571
return new FuncCallStep<>(name, fn, inputClass);
525572
}
@@ -584,20 +631,21 @@ public static EmitStep emit(String name, Consumer<FuncEmitTaskBuilder> cfg) {
584631
* @param <T> input type
585632
* @return an {@link EmitStep}
586633
*/
587-
public static <T> EmitStep emit(String type, Function<T, CloudEventData> fn) {
634+
public static <T> EmitStep emit(String type, SerializableFunction<T, CloudEventData> fn) {
588635
return new EmitStep(null, event(type, fn));
589636
}
590637

591638
/**
592-
* Named variant of {@link #emit(String, Function)}.
639+
* Named variant of {@link #emit(String, SerializableFunction)}.
593640
*
594641
* @param name task name
595642
* @param type CloudEvent type
596643
* @param fn function producing {@link CloudEventData}
597644
* @param <T> input type
598645
* @return a named {@link EmitStep}
599646
*/
600-
public static <T> EmitStep emit(String name, String type, Function<T, CloudEventData> fn) {
647+
public static <T> EmitStep emit(
648+
String name, String type, SerializableFunction<T, CloudEventData> fn) {
601649
return new EmitStep(name, event(type, fn));
602650
}
603651

@@ -678,7 +726,7 @@ public static ListenStep listen(String name, FuncListenSpec spec) {
678726

679727
/**
680728
* Low-level switch case configurer using a custom builder consumer. Prefer the {@link
681-
* #caseOf(Predicate)} helpers when possible.
729+
* #caseOf(SerializablePredicate)} helpers when possible.
682730
*
683731
* @param taskName optional task name
684732
* @param switchCase consumer to configure the {@link FuncSwitchTaskBuilder}
@@ -701,7 +749,7 @@ public static FuncTaskConfigurer switchCase(Consumer<FuncSwitchTaskBuilder> swit
701749

702750
/**
703751
* Convenience to apply multiple {@link SwitchCaseConfigurer} built via {@link
704-
* #caseOf(Predicate)}.
752+
* #caseOf(SerializablePredicate)}.
705753
*
706754
* @param cases case configurers
707755
* @return list configurer
@@ -773,6 +821,11 @@ public static <T> FuncTaskConfigurer switchWhenOrElse(
773821
FuncDSL.cases(caseOf(pred, predClass).then(thenTask), caseDefault(otherwise)));
774822
}
775823

824+
public static <T> FuncTaskConfigurer switchWhenOrElse(
825+
SerializablePredicate<T> pred, String thenTask, FlowDirectiveEnum otherwise) {
826+
return switchWhenOrElse(pred, thenTask, otherwise, ReflectionUtils.inferInputType(pred));
827+
}
828+
776829
/**
777830
* Sugar for a single-case switch with a default task fallback.
778831
*
@@ -789,6 +842,11 @@ public static <T> FuncTaskConfigurer switchWhenOrElse(
789842
list.switchCase(cases(caseOf(pred, predClass).then(thenTask), caseDefault(otherwiseTask)));
790843
}
791844

845+
public static <T> FuncTaskConfigurer switchWhenOrElse(
846+
SerializablePredicate<T> pred, String thenTask, String otherwiseTask) {
847+
return switchWhenOrElse(pred, thenTask, otherwiseTask, ReflectionUtils.inferInputType(pred));
848+
}
849+
792850
/**
793851
* JQ-based condition: if the JQ expression evaluates truthy → jump to {@code thenTask}, otherwise
794852
* follow the {@link FlowDirectiveEnum} given in {@code otherwise}.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public abstract class FuncEventFilterSpec<SELF>
3434
}
3535

3636
/** Sets the event data and the contentType to `application/json` */
37-
public <T> SELF jsonData(Function<T, CloudEventData> function) {
37+
public <T> SELF jsonData(SerializableFunction<T, CloudEventData> function) {
3838
Class<T> clazz = ReflectionUtils.inferInputType(function);
3939
addStep(e -> e.data(new EventDataFunction().withFunction(function, clazz)));
4040
return JSON();

0 commit comments

Comments
 (0)