[Fix #1209] Adding Context and Filter predicate#1224
[Fix #1209] Adding Context and Filter predicate#1224fjtirado merged 2 commits intoserverlessworkflow:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses issue #1209 by expanding Java predicate/function support to optionally receive workflow and task context, enabling context-aware filtering and evaluation across the experimental Java runtime and fluent DSL.
Changes:
- Introduces new context-aware predicate/function types (
ContextPredicate,FilterPredicate,ContextFunction,FilterFunction) plus typed wrappers. - Updates switch/listen/for execution paths to build predicates/functions from the new container/wrapper types.
- Refactors the fluent DSL and tests to use the renamed/updated function interfaces and new switch predicate container type.
Reviewed changes
Copilot reviewed 41 out of 41 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/UntilPredicate.java | Stores predicates as Object (typed wrappers) and implements PredicateContainer to support multiple predicate shapes. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/TypedFilterPredicate.java | Adds typed wrapper for FilterPredicate argument conversion. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/TypedFilterFunction.java | Adds typed wrapper for FilterFunction argument conversion. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/TypedContextPredicate.java | Adds typed wrapper for ContextPredicate argument conversion. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/TypedContextFunction.java | Renames typed context function wrapper to match new ContextFunction interface. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/SwitchCasePredicate.java | New switch-case container supporting plain/typed/context/task-aware predicates. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/SwitchCaseFunction.java | Removes the old SwitchCaseFunction container implementation. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/PredicateContainer.java | Introduces a common interface for types that “carry” a predicate object. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/OutputAsFunction.java | Updates overloads to use FilterFunction / ContextFunction and new typed wrappers. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/LoopPredicateIndexFilter.java | Adds loop predicate shape that receives workflow/task context. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/LoopPredicateIndexContext.java | Adds loop predicate shape that receives workflow context. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/InputFromFunction.java | Updates overloads to use FilterFunction / ContextFunction and new typed wrappers. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/ForTaskFunction.java | Extends while predicate options to include index + workflow/task context forms. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/FilterPredicate.java | Introduces predicate that receives workflow + task context. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/FilterFunction.java | Renames JavaFilterFunction to FilterFunction (context+task-aware function). |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/ExportAsFunction.java | Updates overloads to use FilterFunction / ContextFunction and new typed wrappers. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/EventDataPredicate.java | Adds context-aware predicate overloads for event data filtering. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/ContextPredicate.java | Introduces predicate that receives workflow context. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/ContextFunction.java | Renames JavaContextFunction to ContextFunction (workflow-context-aware function). |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/CallJava.java | Updates call variants and nested types to use ContextFunction / FilterFunction. |
| experimental/lambda/src/test/java/io/serverless/workflow/impl/executors/func/CallTest.java | Updates switch predicate test to use SwitchCasePredicate. |
| experimental/lambda/src/test/java/io/serverless/workflow/impl/executors/func/CallJavaContextFunctionTest.java | Updates test to use ContextFunction. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/expressions/func/JavaExpressionFactory.java | Adds predicate building for new predicate types and typed wrappers; updates priority logic. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaSwitchExecutorBuilder.java | Switch executor now uses SwitchCasePredicate and JavaFuncUtils.from(...). |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaListenExecutorBuilder.java | Listen executor now uses UntilPredicate + JavaFuncUtils.from(...). |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaFuncUtils.java | Replaces old typed-predicate construction helper with predicate-container based predicate building. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaForExecutorBuilder.java | Passes workflow/task context into the new loop predicate signature. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaFilterFunctionCallExecutorBuilder.java | Updates builder to use FilterFunction. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaFilterFunctionCallExecutor.java | Updates executor to call FilterFunction.apply(...). |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaContextFunctionCallExecutorBuilder.java | Updates builder to use ContextFunction. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaContextFunctionCallExecutor.java | Updates executor to call ContextFunction.apply(...). |
| experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLUniqueIdTest.java | Updates test extraction/casts to FilterFunction. |
| experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLTest.java | Updates DSL tests to use FilterFunction. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/spi/FuncTransformations.java | Updates DSL transformation interfaces to accept ContextFunction / FilterFunction. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/spi/FuncTaskTransformations.java | Updates task-specific transformation interfaces to accept ContextFunction / FilterFunction. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/Step.java | Updates DSL Step APIs + Javadoc references to renamed function interfaces. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/ReflectionUtils.java | Updates type inference helpers to accept ContextFunction / FilterFunction. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/FuncDSL.java | Updates DSL entrypoints and internal wrappers to use renamed function interfaces. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/FuncCallStep.java | Updates internal step representation to store ContextFunction / FilterFunction. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncSwitchTaskBuilder.java | Switch DSL builder now constructs SwitchCasePredicate. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncCallTaskBuilder.java | Call-task DSL builder now accepts ContextFunction / FilterFunction. |
Comments suppressed due to low confidence (2)
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/FilterFunction.java:25
- This change renames the public API type
JavaFilterFunctiontoFilterFunction(and similarly for context variants) across modules. That’s a breaking change beyond the stated goal of adding optional context parameters; if intentional, it should be called out in the PR description/release notes and (if needed) provide migration guidance or deprecation shims.
experimental/lambda/src/main/java/io/serverlessworkflow/impl/expressions/func/JavaExpressionFactory.java:136 buildIfFilter(...)still only recognizesPredicateandTypedPredicate. With the newContextPredicate/FilterPredicate(and typed variants),when/ifpredicates stored in metadata will be silently ignored. Extend this method to handle the new predicate types the same waybuildPredicate(...)does.
public Optional<WorkflowPredicate> buildIfFilter(TaskBase task) {
TaskMetadata metadata = task.getMetadata();
if (metadata != null) {
Object obj = metadata.getAdditionalProperties().get(TaskMetadataKeys.IF_PREDICATE);
if (obj instanceof Predicate pred) {
return Optional.of(fromPredicate(pred));
} else if (obj instanceof TypedPredicate pred) {
return Optional.of(fromPredicate(pred));
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/SwitchCasePredicate.java
Outdated
Show resolved
Hide resolved
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/SwitchCasePredicate.java
Outdated
Show resolved
Hide resolved
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/UntilPredicate.java
Outdated
Show resolved
Hide resolved
...ambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaSwitchExecutorBuilder.java
Outdated
Show resolved
Hide resolved
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/ForTaskFunction.java
Show resolved
Hide resolved
.../lambda/src/main/java/io/serverlessworkflow/impl/expressions/func/JavaExpressionFactory.java
Outdated
Show resolved
Hide resolved
...ambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaListenExecutorBuilder.java
Outdated
Show resolved
Hide resolved
...ental/types/src/main/java/io/serverlessworkflow/api/types/func/LoopPredicateIndexFilter.java
Outdated
Show resolved
Hide resolved
...imental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLUniqueIdTest.java
Outdated
Show resolved
Hide resolved
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/SwitchCasePredicate.java
Show resolved
Hide resolved
Signed-off-by: fjtirado <ftirados@redhat.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 41 out of 41 changed files in this pull request and generated 6 comments.
Comments suppressed due to low confidence (1)
experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLTest.java:118
- Test comment and assertion message still reference
JavaFilterFunction, but the API type is nowFilterFunction. Updating these strings will avoid confusion when reading failures and keep tests aligned with the renamed API.
// JavaFilterFunction<T,R> is (T, WorkflowContextData, TaskContextData) -> R
FilterFunction<String, Map<String, Object>> jf =
(val, wfCtx, taskCtx) -> Map.of("wrapped", val, "wfId", wfCtx.instanceData().id());
Workflow wf =
FuncWorkflowBuilder.workflow("step-emit-export")
.tasks(emit("emitWrapped", spec).exportAs(jf)) // chaining on Step
.build();
List<TaskItem> items = wf.getDo();
assertEquals(1, items.size());
Task t = items.get(0).getTask();
assertNotNull(t.getEmitTask(), "EmitTask expected");
// Export is attached to Task
Export ex = t.getEmitTask().getExport();
assertNotNull(ex, "Export should be set via Step.exportAs(JavaFilterFunction)");
assertNotNull(ex.getAs(), "'as' should be populated");
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/ForTaskFunction.java
Show resolved
Hide resolved
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/SwitchCasePredicate.java
Show resolved
Hide resolved
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/FuncCallStep.java
Outdated
Show resolved
Hide resolved
...imental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLUniqueIdTest.java
Show resolved
Hide resolved
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/UntilPredicate.java
Outdated
Show resolved
Hide resolved
.../lambda/src/main/java/io/serverlessworkflow/impl/expressions/func/JavaExpressionFactory.java
Show resolved
Hide resolved
ricardozanini
left a comment
There was a problem hiding this comment.
LGTM, but Co-Pilot is pointing out a few null checks that I think are worth adding.
Yes, I handle them a bit differently from what copilot recommended, if class is null, lets use the non typed variant. |
Signed-off-by: fjtirado <ftirados@redhat.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 41 out of 41 changed files in this pull request and generated 8 comments.
Comments suppressed due to low confidence (1)
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncSwitchTaskBuilder.java:67
- The
Objects.requireNonNullfailure message says "When is required", but this branch is validating thatthenis present for a default case. Update the message to reflect what is actually required (e.g., "Then is required") to avoid confusing users.
if (switchCaseValue.predicate() == null) {
Objects.requireNonNull(switchCaseValue.getThen(), "When is required");
if (switchCaseValue.getThen().getFlowDirectiveEnum() != null) {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| public <T, V> OutputAs withFunction(ContextFunction<T, V> value, Class<T> argClass) { | ||
| setObject(new TypedContextFunction<>(value, argClass)); | ||
| return this; |
|
|
||
| public <T, V> InputFrom withFunction(JavaContextFunction<T, V> value, Class<T> argClass) { | ||
| setObject(new TypedJavaContextFunction<>(value, argClass)); | ||
| public <T, V> InputFrom withFunction(ContextFunction<T, V> value, Class<T> argClass) { |
|
|
||
| public <T, V> ExportAs withFunction(JavaFilterFunction<T, V> value, Class<T> argClass) { | ||
| setObject(new TypedJavaFilterFunction<>(value, argClass)); | ||
| public <T, V> ExportAs withFunction(FilterFunction<T, V> value, Class<T> argClass) { |
| static WorkflowPredicate from(WorkflowApplication application, PredicateContainer source) { | ||
| assert (source.predicate() != null); | ||
| return application | ||
| .expressionFactory() | ||
| .buildPredicate(ExpressionDescriptor.object(source.predicate())); | ||
| } |
| private WorkflowPredicate fromPredicate(ContextPredicate pred) { | ||
| return (w, t, n) -> pred.test(n.asJavaObject(), w); | ||
| } |
| public <T, V> OutputAs withFunction(FilterFunction<T, V> value, Class<T> argClass) { | ||
| setObject(new TypedFilterFunction<>(value, argClass)); | ||
| return this; |
| public <T, V> InputFrom withFunction(FilterFunction<T, V> value, Class<T> argClass) { | ||
| setObject(new TypedFilterFunction<>(value, argClass)); | ||
| return this; |
|
|
||
| public <T, V> ExportAs withFunction(JavaContextFunction<T, V> value, Class<T> argClass) { | ||
| setObject(new TypedJavaContextFunction<>(value, argClass)); | ||
| public <T, V> ExportAs withFunction(ContextFunction<T, V> value, Class<T> argClass) { |
Fix #1209
Also, as suggested by @ricardozanini, Java prefix is removed from functions.