Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@
import io.cloudevents.CloudEventData;
import io.serverlessworkflow.api.types.TaskBase;
import io.serverlessworkflow.api.types.TaskMetadata;
import io.serverlessworkflow.api.types.func.JavaContextFunction;
import io.serverlessworkflow.api.types.func.JavaFilterFunction;
import io.serverlessworkflow.api.types.func.TaskMetadataKeys;
import io.serverlessworkflow.api.types.func.TypedFunction;
import io.serverlessworkflow.api.types.func.TypedJavaContextFunction;
import io.serverlessworkflow.api.types.func.TypedJavaFilterFunction;
import io.serverlessworkflow.api.types.func.TypedPredicate;
import io.serverlessworkflow.impl.WorkflowModelFactory;
import io.serverlessworkflow.impl.WorkflowPredicate;
Expand All @@ -44,6 +48,14 @@ public ObjectExpression buildExpression(ExpressionDescriptor descriptor) {
return (w, t, n) -> func.apply(n.asJavaObject());
} else if (value instanceof TypedFunction func) {
return (w, t, n) -> func.function().apply(n.as(func.argClass()).orElseThrow());
} else if (value instanceof JavaFilterFunction func) {
return (w, t, n) -> func.apply(n.asJavaObject(), w, t);
} else if (value instanceof TypedJavaFilterFunction func) {
return (w, t, n) -> func.function().apply(n.as(func.argClass()).orElseThrow(), w, t);
} else if (value instanceof JavaContextFunction func) {
return (w, t, n) -> func.apply(n.asJavaObject(), w);
} else if (value instanceof TypedJavaContextFunction func) {
return (w, t, n) -> func.function().apply(n.as(func.argClass()).orElseThrow(), w);
} else {
return (w, t, n) -> value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package io.serverless.workflow.impl;

import io.serverlessworkflow.impl.TaskContextData;
import io.serverlessworkflow.impl.WorkflowContextData;
import java.util.Map;

public class JavaFunctions {
Expand All @@ -27,6 +29,15 @@ static String getName(Person person) {
return person.name() + " Javierito";
}

static String getFilterName(
Person person, WorkflowContextData workflowContext, TaskContextData taskContext) {
return person.name() + "_" + workflowContext.instanceData().id() + "_" + taskContext.taskName();
}

static String getContextName(Person person, WorkflowContextData workflowContext) {
return person.name() + "_" + workflowContext.instanceData().id();
}

static Map<String, Object> addJavierito(Map<String, Object> map) {
return Map.of("name", map.get("name") + " Javierito");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import io.serverlessworkflow.api.types.Workflow;
import io.serverlessworkflow.api.types.func.OutputAsFunction;
import io.serverlessworkflow.impl.WorkflowApplication;
import io.serverlessworkflow.impl.WorkflowInstance;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
Expand Down Expand Up @@ -173,4 +174,62 @@ void testPOJOStringExpression() throws InterruptedException, ExecutionException
.isEqualTo("Francisco Javierito");
}
}

@Test
void testPOJOStringExpressionWithContext() throws InterruptedException, ExecutionException {
try (WorkflowApplication app = WorkflowApplication.builder().build()) {
Workflow workflow =
new Workflow()
.withDocument(
new Document().withNamespace("test").withName("testPojo").withVersion("1.0"))
.withDo(
List.of(
new TaskItem(
"doNothing",
new Task()
.withWaitTask(
new WaitTask()
.withWait(
new TimeoutAfter()
.withDurationInline(
new DurationInline().withMilliseconds(10)))))))
.withOutput(
Copy link
Collaborator Author

@fjtirado fjtirado Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Output associated to a workflow, we specify the two arguments function.
Important thing to know is that TaskContext will be null if the three parameter function has been specified here (we should either document that or prevent user passing the three parameter function if the input/output/export is associated to the workflow)

new Output()
.withAs(new OutputAsFunction().withFunction(JavaFunctions::getContextName)));
WorkflowInstance instance =
app.workflowDefinition(workflow).instance(new Person("Francisco", 33));
assertThat(instance.start().get().asText().orElseThrow())
.isEqualTo("Francisco_" + instance.id());
}
}

@Test
void testPOJOStringExpressionWithFilter() throws InterruptedException, ExecutionException {
try (WorkflowApplication app = WorkflowApplication.builder().build()) {
Workflow workflow =
new Workflow()
.withDocument(
new Document().withNamespace("test").withName("testPojo").withVersion("1.0"))
.withDo(
List.of(
new TaskItem(
"doNothing",
new Task()
.withWaitTask(
new WaitTask()
.withOutput(
new Output()
.withAs(
new OutputAsFunction()
Copy link
Collaborator Author

@fjtirado fjtirado Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Output associated to the task, we call three parameter function without issue
We can also call the two/one parameter one if we want.

.withFunction(JavaFunctions::getFilterName)))
.withWait(
new TimeoutAfter()
.withDurationInline(
new DurationInline().withMilliseconds(10)))))));
WorkflowInstance instance =
app.workflowDefinition(workflow).instance(new Person("Francisco", 33));
assertThat(instance.start().get().asText().orElseThrow())
.isEqualTo("Francisco_" + instance.id() + "_doNothing");
}
}
}
4 changes: 4 additions & 0 deletions experimental/types/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-types</artifactId>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-impl-core</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,24 @@ public <T, V> ExportAs withFunction(Function<T, V> value, Class<T> argClass) {
setObject(new TypedFunction<>(value, argClass));
return this;
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Export also existed ;)

public <T, V> ExportAs withFunction(JavaFilterFunction<T, V> value) {
setObject(value);
return this;
}

public <T, V> ExportAs withFunction(JavaFilterFunction<T, V> value, Class<T> argClass) {
setObject(new TypedJavaFilterFunction<>(value, argClass));
return this;
}

public <T, V> ExportAs withFunction(JavaContextFunction<T, V> value) {
setObject(value);
return this;
}

public <T, V> ExportAs withFunction(JavaContextFunction<T, V> value, Class<T> argClass) {
setObject(new TypedJavaContextFunction<>(value, argClass));
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,24 @@ public <T, V> InputFrom withFunction(Function<T, V> value, Class<T> argClass) {
setObject(new TypedFunction<>(value, argClass));
return this;
}

public <T, V> InputFrom withFunction(JavaFilterFunction<T, V> value) {
setObject(value);
return this;
}

public <T, V> InputFrom withFunction(JavaFilterFunction<T, V> value, Class<T> argClass) {
setObject(new TypedJavaFilterFunction<>(value, argClass));
return this;
}

public <T, V> InputFrom withFunction(JavaContextFunction<T, V> value) {
setObject(value);
return this;
}

public <T, V> InputFrom withFunction(JavaContextFunction<T, V> value, Class<T> argClass) {
setObject(new TypedJavaContextFunction<>(value, argClass));
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2020-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.serverlessworkflow.api.types.func;

import io.serverlessworkflow.impl.WorkflowContextData;

@FunctionalInterface
public interface JavaContextFunction<T, R> {
R apply(T object, WorkflowContextData workflowContext);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2020-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.serverlessworkflow.api.types.func;

import io.serverlessworkflow.impl.TaskContextData;
import io.serverlessworkflow.impl.WorkflowContextData;

@FunctionalInterface
public interface JavaFilterFunction<T, R> {
R apply(T object, WorkflowContextData workflowContext, TaskContextData taskContext);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,24 @@ public <T, V> OutputAs withFunction(Function<T, V> value, Class<T> argClass) {
setObject(new TypedFunction<>(value, argClass));
return this;
}

public <T, V> OutputAs withFunction(JavaFilterFunction<T, V> value) {
setObject(value);
return this;
}

public <T, V> OutputAs withFunction(JavaFilterFunction<T, V> value, Class<T> argClass) {
setObject(new TypedJavaFilterFunction<>(value, argClass));
return this;
}

public <T, V> OutputAs withFunction(JavaContextFunction<T, V> value) {
setObject(value);
return this;
}

public <T, V> OutputAs withFunction(JavaContextFunction<T, V> value, Class<T> argClass) {
setObject(new TypedJavaContextFunction<>(value, argClass));
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2020-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.serverlessworkflow.api.types.func;

public record TypedJavaContextFunction<T, V>(
JavaContextFunction<T, V> function, Class<T> argClass) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2020-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.serverlessworkflow.api.types.func;

public record TypedJavaFilterFunction<T, V>(JavaFilterFunction<T, V> function, Class<T> argClass) {}