Files
spring-state-machine-renderer/README.md
Kamil Patryk Kozakowski ea9b8d6cff Improve multi-machine scoping, path binding expansion, and analysis precision.
Expand generic REST path variables into concrete command keys, filter entry points and call chains per machine, and tighten ambiguous routing and switch constraints so layered dispatchers link fewer false positives.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 21:26:13 +02:00

81 lines
3.6 KiB
Markdown

# Spring State Machine Explorer
Static analysis tool to extract and visualize Spring State Machines with deep code traceability.
## Core Modules
- **`state_machine_exporter`**: Java AST analyzer. Scans source code, resolves local Maven/Gradle dependencies, and extracts logic (Lambdas, Actions, Guards) into JSON/PUML.
- **`state_machine_exporter_html`**: Generates an interactive HTML portal with SVG diagrams and rich tooltips.
## Usage
Analysis is **source-first**: the exporter reads project source and build metadata (`pom.xml`, `settings.gradle`) statically. It does **not** run Maven or Gradle against the project being analyzed.
### 1. Extract Metadata (JSON)
```bash
./gradlew :state_machine_exporter:run --args="-i ./my-project -o ./out -f json"
```
Common options:
| Flag | Description |
|------|-------------|
| `-i, --input` | Project directory to scan (defaults to `.`) |
| `-j, --json` | Re-render from an existing JSON export instead of scanning source |
| `-o, --output` | Output directory (default `./out`) |
| `-f, --format` | Comma-separated formats: `json`, `dot`, `puml`, `scxml` |
| `-p, --profiles` | Spring profiles for property placeholder resolution |
| `--event`, `--state` | Enum formatting: `fn` (default), `fqn`, `sn` |
| `--debug` | Verbose analysis logging and unresolved chain diagnostics |
| `--no-diamonds` | Render choice/junction states as regular nodes (default: diamonds) |
| `--include-generated-sources` | Also scan `target/` / `build/` generated `.java` trees (default: on) |
| `--no-inline-accessors` | Disable accessor indexing/inlining (enabled by default) |
### 2. Generate Interactive Portal (HTML)
```bash
./gradlew :state_machine_exporter_html:run --args="-i ./my-project -o ./out_html"
```
HTML-specific options:
| Flag | Description |
|------|-------------|
| `-f, --flows` | Custom `flows.json` path |
| `-m, --machine` | Export only machines whose name contains this filter |
| `--open` | Open the generated portal in the default browser |
| `--no-metadata-pane` | Hide the left metadata pane (entry points, flows) |
| `--no-diamonds` | Render choice pseudostates as normal nodes |
| `--debug` | Same diagnostic mode as the core exporter |
| `--include-generated-sources` | Same generated-source scanning as the core exporter |
| `-p, --profiles` | Spring profiles for property resolution |
## Business Flows
Define sequence of events in `src/main/resources/flows.json`:
```json
[
{
"name": "Order Success",
"description": "Happy path for order placement",
"steps": ["PAY", "CHECK_AVAILABILITY->PENDING", "SHIP"]
}
]
```
## JSON Structure
- `metadata.entryPoints`: REST, WebFlux, and JMS entry points.
- `metadata.callChains`: Trace from API call to machine trigger (`sendEvent`).
- `transitions.actions[].internalLogic`: Extracted source code/lambdas.
- `metadata.properties`: Dictionary of all detected Spring profiles.
## Static analysis: accessor inlining
During scan, the exporter builds an **accessor index** of trivial getters, setters, record components, and constant-returning methods. At analysis time, `AccessorResolver` uses this index first (O(1) lookup), then falls back to constructor/field tracing and method-body evaluation.
This improves resolution of DTO/event chains such as `request.getPayload().getType()` without running Maven or Gradle on the target project.
```bash
# Enabled by default; disable for debugging or A/B comparison
./gradlew :state_machine_exporter:run --args="-i ./my-project -o ./out --no-inline-accessors"
```
Pipeline components live under `analysis/pipeline/` (`AccessorResolver`, `ResolutionBudget`, `MethodInvocationUnwrapper`, `FieldInitializerFinder`, `LibraryUnwrapRegistry`).