Add FlowStep with backward-compatible JSON (strings or objects), precompute linkKey in HTML export, and document precise flow highlighting in flows.json. Co-authored-by: Cursor <cursoragent@cursor.com>
88 lines
4.0 KiB
Markdown
88 lines
4.0 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 |
|
|
| `--no-inline-accessors` | Disable accessor indexing/inlining (enabled by default) |
|
|
| `-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",
|
|
{ "source": "com.example.order.OrderState.PAID", "event": "com.example.order.OrderEvent.SHIP" }
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
Event-only strings remain supported but do not highlight in the HTML explorer unless paired with a source state. Use `{source, event}` objects for precise transition highlighting.
|
|
|
|
## 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`).
|