private static Map<String, Object> getStateDetails(final Flow flowDefinition, final String stateId) {
        val state = (State) flowDefinition.getState(stateId);
        val stateMap = new LinkedHashMap<String, Object>();

        if (!state.getAttributes().asMap().isEmpty()) {
            stateMap.put("attributes", CollectionUtils.wrap(state.getAttributes()));
        }
        if (StringUtils.isNotBlank(state.getCaption())) {
            stateMap.put("caption", state.getCaption());
        }

        var acts = StreamSupport.stream(state.getEntryActionList().spliterator(), false)
            .map(SpringWebflowEndpoint::convertActionToString)
            .collect(Collectors.toList());

        if (!acts.isEmpty()) {
            stateMap.put("entryActions", acts);
        }

        if (state instanceof final ActionState actionState) {
            acts = StreamSupport.stream(actionState.getActionList().spliterator(), false)
                .map(SpringWebflowEndpoint::convertActionToString)
                .collect(Collectors.toList());
            if (!acts.isEmpty()) {
                stateMap.put("actionList", acts);
            }
        }

        if (state instanceof EndState) {
            stateMap.put("isEndState", Boolean.TRUE);
        }
        if (state instanceof DecisionState) {
            stateMap.put("isDecisionState", Boolean.TRUE);
        }

        if (state instanceof final SubflowState subflowState) {
            var field = ReflectionUtils.findField(subflowState.getClass(), "subflow");
            ReflectionUtils.makeAccessible(Objects.requireNonNull(field));
            val subflowExpr = (Expression) ReflectionUtils.getField(field, subflowState);
            field = ReflectionUtils.findField(subflowExpr.getClass(), "subflowId");
            ReflectionUtils.makeAccessible(Objects.requireNonNull(field));
            val subflowId = (String) ReflectionUtils.getField(field, subflowExpr);
            stateMap.put("subflowId", subflowId);
            stateMap.put("isSubflowState", Boolean.TRUE);
        }

        if (state.isViewState()) {
            val viewState = (ViewState) state;

            stateMap.put("isViewState", state.isViewState());
            stateMap.put("isRedirect", viewState.getRedirect());

            acts = StreamSupport.stream(viewState.getRenderActionList().spliterator(), false)
                .map(SpringWebflowEndpoint::convertActionToString)
                .collect(Collectors.toList());

            if (!acts.isEmpty()) {
                stateMap.put("renderActions", acts);
            }

            acts = Arrays.stream(viewState.getVariables())
                .map(variable -> variable.getName() + " -> " + variable.getValueFactory().toString())
                .collect(Collectors.toList());

            if (!acts.isEmpty()) {
                stateMap.put("viewVariables", acts);
            }

            val field = ReflectionUtils.findField(viewState.getViewFactory().getClass(), "viewId");
            if (field != null) {
                ReflectionUtils.makeAccessible(field);
                val exp = (Expression) ReflectionUtils.getField(field, viewState.getViewFactory());
                stateMap.put("viewId", StringUtils.defaultIfBlank(Objects.requireNonNull(exp).getExpressionString(), exp.getValue(null).toString()));
            } else if (viewState.getViewFactory() instanceof final ActionExecutingViewFactory factory) {
                if (factory.getAction() instanceof final ExternalRedirectAction redirect) {
                    val uri = ReflectionUtils.findField(redirect.getClass(), "resourceUri");
                    ReflectionUtils.makeAccessible(Objects.requireNonNull(uri));
                    val exp = (Expression) ReflectionUtils.getField(uri, redirect);
                    stateMap.put("viewId", "externalRedirect -> #{" + Objects.requireNonNull(exp).getExpressionString() + '}');
                } else {
                    stateMap.put("viewId", factory.getAction().toString());
                }
            } else {
                LOGGER.info("Field viewId cannot be located on view state [{}]", state);
            }
        }

        if (state instanceof final TransitionableState stDef) {
            acts = StreamSupport.stream(stDef.getExitActionList().spliterator(), false)
                .map(SpringWebflowEndpoint::convertActionToString)
                .collect(Collectors.toList());

            if (!acts.isEmpty()) {
                stateMap.put("exitActions", acts);
            }

            acts = Arrays.stream(stDef.getTransitions())
                .map(tr -> tr.getId() + " -> " + tr.getTargetStateId())
                .collect(Collectors.toList());

            if (!acts.isEmpty()) {
                stateMap.put("transitions", acts);
            }
        }

        return stateMap;
    }
This is {@link SpringWebflowEndpoint}.

@author Misagh Moayyed
@since 5.1.0
support/cas-server-support-reports-core/src/main/java/org/apereo/cas/web/report/SpringWebflowEndpoint.java