Skip to content

Allow exportAs transformation to access the current task output #1201

@mcruzdev

Description

@mcruzdev

Description

When using exportAs with a JavaContextFunction that accesses workflowContext.instanceData().input(), the method returns null instead of the original workflow input, causing a NullPointerException.

Expected Behavior

workflowContext.instanceData().input() should return the original workflow input data that was passed to def.instance(submission).start().

Actual Behavior

workflowContext.instanceData().input() returns null, causing:

java.lang.NullPointerException
at java.base/java.util.Optional.of(Optional.java:113)
at io.serverlessworkflow.impl.model.jackson.JacksonModel.convert(JacksonModel.java:99)
at io.serverlessworkflow.impl.AbstractWorkflowModel.as(AbstractWorkflowModel.java:45)

Minimal Reproducer

import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.function;
import io.serverlessworkflow.api.types.Workflow;
import io.serverlessworkflow.fluent.func.FuncWorkflowBuilder;
import io.serverlessworkflow.impl.WorkflowApplication;
import io.serverlessworkflow.impl.WorkflowContextData;
import io.serverlessworkflow.impl.WorkflowDefinition;
import io.serverlessworkflow.impl.WorkflowModel;

public class WorkflowContextInputTest {
    
    public record Input(String name, int value) {}
    public record Output(int result) {}
    public record Combined(String name, int result) {}
    
    public static void main(String[] args) {
        Workflow workflow = FuncWorkflowBuilder.workflow("test")
            .tasks(
                // Step 1: Process input
                function("process",
                    (Input input) -> new Output(input.value() * 2),
                    Input.class)
                .exportAs(
                    (Output output, WorkflowContextData context) -> {
                        // ❌ THIS RETURNS NULL:
                        WorkflowModel originalInput = context.instanceData().input();
                        Input input = originalInput.as(Input.class).orElseThrow();
                        
                        return new Combined(input.name(), output.result());
                    },
                    Output.class)
            )
            .build();
        
        WorkflowApplication app = WorkflowApplication.builder().build();
        WorkflowDefinition def = app.workflowDefinition(workflow);
        
        // This will throw NullPointerException
        WorkflowModel result = def.instance(new Input("test", 5)).start().join();
    }
}

Workaround

Pass data forward through the workflow steps instead of accessing it from the context:

function("process",
    (Input input) -> new Combined(input.name(), input.value() * 2),
    Input.class)

Metadata

Metadata

Assignees

Labels

javaPull requests that update java codespec:1.0.0

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions