Forking an Entity

Forking a single entity

Given a forkable Ninja, the simplest possible fork is:

Ninja next = original.fork(ForkMode.ToNext);

Under the hood, Forkable.fork(ForkMode) calls fork() to obtain the Forker, then dispatches to toCopy(), toNext(), or toPrevious() based on the mode.

What ends up on the result

The new entity carries:

  • a fresh UUID (assuming your Forker calls UUID.randomUUID());

  • forkedFrom populated by original.toForkSources(mode) — see Lineage;

  • references to other forkable entities replaced with fork-ref shells (UUID + lineage, no payload), via ForkRefAware.ofNullable(…​);

  • plain data fields copied directly.

Handling references

When a forked entity points at another forkable entity, you have two choices:

  1. Inline shell — wrap the reference in ForkRefAware.ofNullable(other, mode). The parent now has a stable shell that the persistence layer can save without recursively materialising the original.

  2. Resolved id — call forkContext.resolveIdentifier(other) for the new SourceIdentifier of the (planned) forked counterpart, and store that. Use this when the referenced entity is also being forked in the same operation: both ends will resolve to the same generated UUID.

Validation hooks

Two checks belong on the service path before invoking the fork:

  1. ForkSource.valid(cmd.getForkFrom()) — non-null mode and identifier; throws InvalidForkOperation otherwise.

  2. forkMode.sourceYearMatchesTargetYear(sourcePeriod, targetPeriod) — periods line up with the mode.