Flow inheritance allows one flow to inherit the configuration of another flow. Inheritance can occur at both the flow and state levels. A common use case is for a parent flow to define global transitions and exception handlers, then each child flow can inherit those settings.
In order for a parent flow to be found, it must be added to the flow-registry
just like any other flow.
Flow inheritance is similar to Java inheritance in that elements defined in a parent are exposed via the child, however, there are key differences.
A child flow cannot override an element from a parent flow. Similar elements between the parent and child flows will be merged. Unique elements in the parent flow will be added to the child.
A child flow can inherit from multiple parent flows. Java inheritance is limited to a single class.
Flow level inheritance is defined by the parent
attribute on the flow
element.
The attribute contains a comma separated list of flow identifiers to inherit from.
The child flow will inherit from each parent in the order it is listed adding elements and content to the resulting flow.
The resulting flow from the first merge will be considered the child in the second merge, and so on.
<flow parent="common-transitions, common-states">
State level inheritance is similar to flow level inheritance, except only one state inherits from the parent, instead of the entire flow.
Unlike flow inheritance, only a single parent is allowed. Additionally, the identifier of the flow state to inherit from must also be defined. The identifiers for the flow and the state within that flow are separated by a #.
The parent and child states must be of the same type. For instance a view-state cannot inherit from an end-state, only another view-state.
<view-state id="child-state" parent="parent-flow#parent-view-state">
Often parent flows are not designed to be executed directly.
In order to protect these flows from running, they can be marked as abstract
.
If an abstract flow attempts to run, a FlowBuilderException
will be thrown.
<flow abstract="true">
When a child flow inherits from it's parent, essentially what happens is that the parent and child are merged together to create a new flow. There are rules for every element in the Web Flow definition language that govern how that particular element is merged.
There are two types of elements: mergeable and non-mergeable. Mergeable elements will always attempt to merge together if the elements are similar. Non-mergeable elements in a parent or child flow will always be contained in the resulting flow intact. They will not be modified as part of the merge process.
Note | |
---|---|
Paths to external resources in the parent flow should be absolute. Relative paths will break when the two flows are merged unless the parent and child flow are in the same directory. Once merged, all relative paths in the parent flow will become relative to the child flow. |
If the elements are of the same type and their keyed attribute are identical, the content of the parent element will be merged with the child element. The merge algorithm will continue to merge each sub-element of the merging parent and child. Otherwise the parent element is added as a new element to the child.
In most cases, elements from a parent flow that are added will be added after elements in the child flow. Exceptions to this rule include action elements (evaluate, render and set) which will be added at the beginning. This allows for the results of parent actions to be used by child actions.
Mergeable elements are:
action-state: id
attribute: name
decision-state: id
end-state: id
flow: always merges
if: test
on-end: always merges
on-entry: always merges
on-exit: always merges
on-render: always merges
on-start: always merges
input: name
output: name
secured: attributes
subflow-state: id
transition: on and on-exception
view-state: id