Skip to content

Instantly share code, notes, and snippets.

@phlego
Created November 18, 2022 06:41
Show Gist options
  • Save phlego/108479f7f9a7d4327f3326a5c729419c to your computer and use it in GitHub Desktop.
Save phlego/108479f7f9a7d4327f3326a5c729419c to your computer and use it in GitHub Desktop.
Generate Mermaid Diagram from Spring State Machine
package com.phl.statemachine;
import org.springframework.statemachine.StateMachine;
public class StateMachineMermaidGenerator {
public static <S, E> String generate(StateMachine<S, E> stateMachine) {
System.out.println("Generating mermaid 🧜\n");
StringBuilder mmBuilder = new StringBuilder();
mmBuilder.append("%% States %%\n");
generateStates(stateMachine, mmBuilder);
mmBuilder.append("\n%% Transitions %%\n");
generateTransitions(stateMachine, mmBuilder);
return mmBuilder.toString();
}
private static <S, E> void generateStates(StateMachine<S, E> stateMachine, StringBuilder mmBuilder) {
stateMachine.getStates().forEach(state -> mmBuilder.append(String.format("%s(%s)\n", state.getId(), state.getId())));
}
private static <S, E> void generateTransitions(StateMachine<S, E> stateMachine, StringBuilder mmBuilder) {
stateMachine.getTransitions().forEach(transition -> {
S source = transition.getSource().getId();
S target = transition.getTarget().getId();
E event = transition.getTrigger().getEvent();
mmBuilder.append(String.format("%s -->|%s| %s\n", source, event, target));
});
}
}
@micoli
Copy link

micoli commented Dec 29, 2024

I had made some little improvments on this generator :

package com.phl.statemachine;

import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.trigger.TimerTrigger;

public class StateMachineMermaidGenerator {

  public static <S, E> String generate(StateMachine<S, E> stateMachine) {
    StringBuilder mmBuilder = new StringBuilder();

    mmBuilder.append("sequenceDiagram\n");
    generateStates(stateMachine, mmBuilder);
    generateTransitions(stateMachine, mmBuilder);

    return mmBuilder.toString();
  }

  private static <S, E> void generateStates(StateMachine<S, E> stateMachine, StringBuilder mmBuilder) {
    stateMachine.getStates().forEach(state -> mmBuilder.append(String.format("participant %s\n", state.getId())));
  }

  private static <S, E> void generateTransitions(StateMachine<S, E> stateMachine, StringBuilder mmBuilder) {
    stateMachine.getTransitions().forEach(transition -> {
      S source = transition.getSource().getId();
      S target = transition.getTarget().getId();
      E event = transition.getTrigger().getEvent();
      String guard = transition.getGuard() == null
              ? ""
              : " G";
      String actions = transition.getActions().isEmpty()
              ? ""
              : String.format(" %2dA", transition.getActions().size());
      String name= (transition.getTrigger() instanceof TimerTrigger<S,E>)
              ?"timer"
              :event.toString();

      mmBuilder.append(String.format("%s-->>%s: %s |%s%s\n", source, target, name, guard, actions));
    });
  }
}


@phlego
Copy link
Author

phlego commented Dec 30, 2024

Thank you very much @micoli 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment