ForkAttempt
Overview
ForkAttempt<T> records the outcome of a single fork step inside a larger bulk operation.
It’s a record with three slots:
public record ForkAttempt<T>(
Command cmd, // the command that drove this step
T result, // populated on success
Problem problem // populated on failure
) { }
Exactly one of result and problem is non-null on a well-formed instance.
The accompanying cmd lets the caller correlate the outcome with the input that produced it — useful for partial-success error reporting in the response.
ForkAttempt.from
The static factory ForkAttempt.from(supplier, invoker) is the workhorse.
It composes:
-
a command supplier — produces the command for this step (the place validations might fail), and
-
a command invoker — actually runs the command (the place the service might fail).
ForkAttempt<Ninja> outcome = ForkAttempt.from(
() -> generator.generateNinjaCommand(ctx, originalNinja),
cmd -> ninjaService.create(cmd)
);
Any ThrowableProblem raised by either lambda is caught, converted to a Problem, and packaged into the returned ForkAttempt.
Other exception types continue to propagate — only domain problems are converted, so genuine bugs still surface.
This keeps the bulk-fork loop simple: each step is independent, the outer loop never has to handle exceptions, and the caller gets a structured list it can render into a partial-success response (see Bulk Forking).