There's currently no common way using the State Machine builder to do that.
By definition each state transition should be explicitly defined in the configuration.
It's another question to discuss if this is a correct approach in the SM world:
If any of A1, A2, A3 results in an exception being thrown, the state
machine should go to E1.
It's debatable if the SM should go to an error state or should stay in the same state or revert to a previous state and so on.
My understanding is that having a common error state to transition to, when error happens in any other state, is not a good approach.
It really depends on what you need to do with the error.
For example if you want to signal on the calling code or propagate the error outside of the stateMachine, you can use the StateContext or the SM ExtendedContext for that.
You can insert a custom flag (e.g. "hasError") and the Exception itself, and expose that to your caller code, but this is not very elegant. Someone should check the presence of that flag on each invocation and notify the caller code (or the caller code itself should check that, and it's ugly).
Another approach would be to clear the stateContext and stay in the same state, waiting for some retry logic to kick in.
Or in your errorAction you can send the ErrorEvent to your SM and pass whatever info is needed in the SM Context, which I believe is the approach you've chosen.
Either way - all transitions should be present in the StateMachineModel
.
This model can be created using the builder approach, or you can create it programatically (where will be easier for example to iterate across all existing states and just define 1 extra transition to the error state).
@Override
public StateMachineModel<String, String> build() {
ConfigurationData<String, String> configurationData = new ConfigurationData<>();
Collection<StateData<String, String>> stateData = new ArrayList<>();
stateData.add(new StateData<String, String>("S1", true));
stateData.add(new StateData<String, String>("S2"));
stateData.add(new StateData<String, String>("S3"));
stateData.add(new StateData<String, String>("ERROR_STATE"));
StatesData<String, String> statesData = new StatesData<>(stateData);
Collection<TransitionData<String, String>> transitionData = new ArrayList<>();
transitionData.add(new TransitionData<String, String>("S1", "S2", "E1"));
stateData.forEach(state -> {
if (state.getState() != ERROR_STATE) {
transitionData.add(new TransitionData<String, String>(state.getState(), "ERROR_STATE", "ERROR_EVENT"));
}
});
TransitionsData<String, String> transitionsData = new TransitionsData<>(transitionData);
StateMachineModel<String, String> stateMachineModel = new DefaultStateMachineModel<String, String>(configurationData,
statesData, transitionsData);
return stateMachineModel;
}