diff --git a/README.md b/README.md index 22196e4..7a83f09 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,45 @@ Static analysis tool to extract and visualize Spring State Machines with deep co ## 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" ``` -*Supports `--profiles prod` to resolve Spring property placeholders.* + +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`: diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/EntryPointEnricher.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/EntryPointEnricher.java index 873cbce..ccda638 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/EntryPointEnricher.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/EntryPointEnricher.java @@ -17,7 +17,8 @@ public class EntryPointEnricher implements AnalysisEnricher { log.info("Enriching {} with entry points", result.getName()); List entryPoints = intelligence.findEntryPoints(); - + entryPoints = MachineScopeFilter.filterEntryPointsForMachine(entryPoints, result.getName(), context); + result.addMetadata(CodebaseMetadata.builder() .entryPoints(entryPoints) .build()); diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/MachineScopeFilter.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/MachineScopeFilter.java index 094c307..fe891b3 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/MachineScopeFilter.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/MachineScopeFilter.java @@ -3,11 +3,13 @@ package click.kamil.springstatemachineexporter.analysis.enricher; import click.kamil.springstatemachineexporter.analysis.enricher.routing.BeanResolutionEngine; import click.kamil.springstatemachineexporter.analysis.enricher.routing.HeuristicBeanResolutionEngine; import click.kamil.springstatemachineexporter.analysis.model.CallChain; +import click.kamil.springstatemachineexporter.analysis.model.EntryPoint; import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; import java.util.ArrayList; import java.util.List; +import java.util.Locale; /** * Filters codebase-wide analysis artifacts to those relevant for a single state machine config. @@ -47,6 +49,89 @@ public final class MachineScopeFilter { return filtered; } + public static List filterEntryPointsForMachine( + List entryPoints, String machineName, CodebaseContext context) { + if (entryPoints == null || machineName == null) { + return entryPoints == null ? List.of() : entryPoints; + } + String machineDomain = extractMachineDomainKey(machineName); + List filtered = new ArrayList<>(); + for (EntryPoint entryPoint : entryPoints) { + if (isEntryPointForMachine(entryPoint, machineDomain, machineName, context)) { + filtered.add(entryPoint); + } + } + return filtered; + } + + private static boolean isEntryPointForMachine( + EntryPoint entryPoint, String machineDomain, String machineName, CodebaseContext context) { + if (entryPoint == null) { + return false; + } + String path = entryPoint.getMetadata() != null ? entryPoint.getMetadata().get("path") : null; + if (path != null) { + String pathDomain = inferDomainFromPath(path); + if (pathDomain != null && machineDomain != null && !domainsMatch(pathDomain, machineDomain)) { + return false; + } + if (pathDomain == null && path.contains("{")) { + return true; + } + } + CallChain probe = CallChain.builder() + .entryPoint(entryPoint) + .methodChain(List.of(entryPoint.getClassName() + "." + entryPoint.getMethodName())) + .build(); + return ROUTING.isRoutedToCorrectMachine(probe, machineName, context); + } + + private static String inferDomainFromPath(String path) { + String lower = path.toLowerCase(Locale.ROOT); + if (lower.contains("/orders") || lower.contains("order.")) { + return "ORDER"; + } + if (lower.contains("/documents") || lower.contains("document.")) { + return "DOCUMENT"; + } + return null; + } + + private static boolean domainsMatch(String pathDomain, String machineDomain) { + String normalizedPath = normalizeDomainKey(pathDomain); + String normalizedMachine = normalizeDomainKey(machineDomain); + return normalizedPath.equalsIgnoreCase(normalizedMachine) + || normalizedMachine.startsWith(normalizedPath) + || normalizedPath.startsWith(normalizedMachine); + } + + private static String extractMachineDomainKey(String machineName) { + String simple = machineName.substring(machineName.lastIndexOf('.') + 1); + String upper = simple.toUpperCase(Locale.ROOT); + for (String marker : List.of("STATEMACHINECONFIGURATION", "STATEMACHINE", "CONFIGURATION", "CONFIG")) { + int idx = upper.indexOf(marker); + if (idx > 0) { + return normalizeDomainKey(upper.substring(0, idx)); + } + } + int stateIdx = upper.indexOf("STATE"); + if (stateIdx > 0) { + return normalizeDomainKey(upper.substring(0, stateIdx)); + } + return normalizeDomainKey(upper); + } + + private static String normalizeDomainKey(String domain) { + if (domain == null || domain.isEmpty()) { + return domain; + } + String upper = domain.toUpperCase(Locale.ROOT); + if (upper.startsWith("STANDARD") && upper.length() > "STANDARD".length()) { + return upper.substring("STANDARD".length()); + } + return upper; + } + private static boolean isTriggerForMachine(TriggerPoint trigger, String machineName, CodebaseContext context) { if (trigger == null) { return false; diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java index dc8bb5f..491722d 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java @@ -3,6 +3,7 @@ package click.kamil.springstatemachineexporter.analysis.enricher; import click.kamil.springstatemachineexporter.analysis.model.AnalysisResult; import click.kamil.springstatemachineexporter.analysis.model.CallChain; import click.kamil.springstatemachineexporter.analysis.model.CodebaseMetadata; +import click.kamil.springstatemachineexporter.analysis.model.EntryPoint; import click.kamil.springstatemachineexporter.analysis.model.MatchedTransition; import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; import click.kamil.springstatemachineexporter.analysis.service.CodebaseIntelligenceProvider; @@ -95,10 +96,12 @@ public class TransitionLinkerEnricher implements AnalysisEnricher { List scopedTriggers = MachineScopeFilter.filterTriggersForMachine( result.getMetadata().getTriggers(), result.getName(), context); + List scopedEntryPoints = MachineScopeFilter.filterEntryPointsForMachine( + result.getMetadata().getEntryPoints(), result.getName(), context); CodebaseMetadata updatedMetadata = CodebaseMetadata.builder() .triggers(scopedTriggers) - .entryPoints(result.getMetadata().getEntryPoints()) + .entryPoints(scopedEntryPoints) .callChains(updatedChains) .properties(result.getMetadata().getProperties()) .build(); diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/routing/HeuristicBeanResolutionEngine.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/routing/HeuristicBeanResolutionEngine.java index dd998ff..16482bf 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/routing/HeuristicBeanResolutionEngine.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/routing/HeuristicBeanResolutionEngine.java @@ -2,6 +2,7 @@ package click.kamil.springstatemachineexporter.analysis.enricher.routing; import click.kamil.springstatemachineexporter.analysis.model.CallChain; import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; +import org.eclipse.jdt.core.dom.TypeDeclaration; import java.util.HashSet; import java.util.Set; @@ -110,15 +111,51 @@ public class HeuristicBeanResolutionEngine implements BeanResolutionEngine { return false; } } - return true; + return context == null || isSingleStateMachine(context); + } + + private int countStateMachines(CodebaseContext context) { + if (context == null) { + return 0; + } + Set machines = new HashSet<>(); + for (TypeDeclaration td : context.findEntryPointClasses( + java.util.List.of("EnableStateMachineFactory", "EnableStateMachine"))) { + String fqn = context.getFqn(td); + if (fqn != null) { + machines.add(fqn); + } + } + for (TypeDeclaration td : context.getTypeDeclarations()) { + if (td == null || td.isInterface()) { + continue; + } + if (context.extendsStateMachineConfigurerAdapter(td)) { + String fqn = context.getFqn(td); + if (fqn != null) { + machines.add(fqn); + } + } + } + if (!machines.isEmpty()) { + return machines.size(); + } + return context.findBeanMethodsReturning( + java.util.Set.of("StateMachine", "StateMachineFactory", "StateMachineModelFactory")).size(); } private boolean isDomainMatch(String smPackage, String chainPackage, String smPrefix, String chainPrefix) { - if (smPackage == null || chainPackage == null || smPackage.isEmpty() || chainPackage.isEmpty()) return false; - - if (smPackage.startsWith(chainPackage) || chainPackage.startsWith(smPackage)) { + if (smPackage == null || chainPackage == null || smPackage.isEmpty() || chainPackage.isEmpty()) { + return false; + } + + if (smPackage.equals(chainPackage)) { return true; } + + if (!chainPackage.startsWith(smPackage + ".") && !smPackage.startsWith(chainPackage + ".")) { + return false; + } // Find deepest common package root String[] p1 = smPackage.split("\\."); @@ -371,10 +408,6 @@ public class HeuristicBeanResolutionEngine implements BeanResolutionEngine { } private boolean isSingleStateMachine(CodebaseContext context) { - if (context == null) return false; - int count = 0; - count += context.findEntryPointClasses(java.util.List.of("EnableStateMachineFactory", "EnableStateMachine")).size(); - count += context.findBeanMethodsReturning(java.util.Set.of("StateMachine", "StateMachineFactory", "StateMachineModelFactory")).size(); - return count <= 1; + return countStateMachines(context) <= 1; } } diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluator.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluator.java index 46becd0..45b6cb4 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluator.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluator.java @@ -74,9 +74,10 @@ public final class BooleanConstraintEvaluator { if (bindings == null || bindings.isEmpty()) { return true; } - for (String varName : extractEqualityVariables(constraint)) { - if (!bindings.containsKey(varName) || varName.equals(bindings.get(varName))) { - return true; + Set equalityVars = extractEqualityVariables(constraint); + for (String varName : equalityVars) { + if (!bindings.containsKey(varName)) { + return false; } } String expr = constraint; diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java index 918b0c5..dc2bdb2 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java @@ -104,33 +104,46 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine { List startMethods = new ArrayList<>(); startMethods.add(startMethod); - boolean foundAny = false; - for (TriggerPoint tp : triggers) { - String targetMethod = tp.getClassName() + "." + tp.getMethodName(); - List> allPaths = new ArrayList<>(); - for (String sMethod : startMethods) { - allPaths.addAll(pathFinder.findAllPaths(sMethod, targetMethod, callGraph, new HashSet<>())); - } - Set> uniquePaths = new LinkedHashSet<>(allPaths); - for (List path : uniquePaths) { - if (!pathBindingEvaluator.isPathCompatible(path, callGraph, pathFinder)) { - continue; - } - foundAny = true; - TriggerPoint resolvedTp = resolveTriggerPointParameters(tp, path, callGraph); - if (resolvedTp != null) { - String contextMachineId = pathFinder.extractContextMachineId(path, callGraph); - chains.add(CallChain.builder() - .entryPoint(ep) - .triggerPoint(resolvedTp) - .methodChain(path) - .contextMachineId(contextMachineId) - .build()); - } - } + List> bindingVariants = + EntryPointBindingExpander.expandPathVariableBindings(ep, context, callGraph); + if (bindingVariants.isEmpty()) { + bindingVariants = List.of(Map.of()); } - if (!foundAny && log.isDebugEnabled()) { - log.debug("Entry point {} ({}) did not reach any trigger points. Graph nodes available: {}", ep.getName(), startMethod, callGraph.keySet()); + + for (Map initialBindings : bindingVariants) { + EntryPoint chainEntryPoint = initialBindings.isEmpty() + ? ep + : EntryPointBindingExpander.withResolvedPath(ep, initialBindings); + + boolean foundAny = false; + for (TriggerPoint tp : triggers) { + String targetMethod = tp.getClassName() + "." + tp.getMethodName(); + List> allPaths = new ArrayList<>(); + for (String sMethod : startMethods) { + allPaths.addAll(pathFinder.findAllPaths(sMethod, targetMethod, callGraph, new HashSet<>())); + } + Set> uniquePaths = new LinkedHashSet<>(allPaths); + for (List path : uniquePaths) { + if (!pathBindingEvaluator.isPathCompatible(path, callGraph, pathFinder, initialBindings)) { + continue; + } + foundAny = true; + TriggerPoint resolvedTp = resolveTriggerPointParameters(tp, path, callGraph); + if (resolvedTp != null) { + String contextMachineId = pathFinder.extractContextMachineId(path, callGraph); + chains.add(CallChain.builder() + .entryPoint(chainEntryPoint) + .triggerPoint(resolvedTp) + .methodChain(path) + .contextMachineId(contextMachineId) + .build()); + } + } + } + if (!foundAny && log.isDebugEnabled()) { + log.debug("Entry point {} ({}) did not reach any trigger points. Graph nodes available: {}", + chainEntryPoint.getName(), startMethod, callGraph.keySet()); + } } } return chains; diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstantExtractor.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstantExtractor.java index dfb8b56..3b06902 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstantExtractor.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstantExtractor.java @@ -299,7 +299,8 @@ public class ConstantExtractor { if (budget == null) { budget = ResolutionBudget.defaults(); } - if (budget.isMethodReturnExhausted(depth)) { + final ResolutionBudget activeBudget = budget; + if (activeBudget.isMethodReturnExhausted(depth)) { log.debug("Exiting resolveMethodReturnConstant early (depth limit) for {}.{}", className, methodName); return Collections.emptyList(); } @@ -309,7 +310,7 @@ public class ConstantExtractor { return Collections.emptyList(); } - Optional indexedAccessor = lookupIndexedGetter(className, methodName, budget); + Optional indexedAccessor = lookupIndexedGetter(className, methodName, activeBudget); TypeDeclaration tempTd = contextCu != null ? context.getTypeDeclaration(className, contextCu) : null; if (tempTd == null) { tempTd = context.getTypeDeclaration(className); @@ -359,7 +360,8 @@ public class ConstantExtractor { if (targetTd == null) targetTd = context.getTypeDeclaration(cName); if (targetTd != null && context.findMethodDeclaration(targetTd, mName, true) != null) { - List delegationResult = resolveMethodReturnConstant(cName, mName, depth + 1, visited, contextCu); + List delegationResult = resolveMethodReturnConstant( + cName, mName, depth + 1, visited, contextCu, activeBudget); constants.addAll(delegationResult); handled = true; } @@ -378,7 +380,8 @@ public class ConstantExtractor { if (targetTd == null) targetTd = context.getTypeDeclaration(cName); if (targetTd != null && context.findMethodDeclaration(targetTd, mName, true) != null) { - List delegationResult = resolveMethodReturnConstant(cName, mName, depth + 1, visited, contextCu); + List delegationResult = resolveMethodReturnConstant( + cName, mName, depth + 1, visited, contextCu, activeBudget); constants.addAll(delegationResult); handled = true; } @@ -425,7 +428,7 @@ public class ConstantExtractor { if (impls != null) { for (String implName : impls) { List delegationResult = resolveMethodReturnConstant( - implName, methodName, depth + 1, visited, contextCu, budget); + implName, methodName, depth + 1, visited, contextCu, activeBudget); constants.addAll(delegationResult); } } diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstructorAnalyzer.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstructorAnalyzer.java index 838e394..bcab312 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstructorAnalyzer.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstructorAnalyzer.java @@ -72,7 +72,8 @@ public class ConstructorAnalyzer { targetClass = context.getFqn(targetTd); } } - results.addAll(constantExtractor.resolveMethodReturnConstant(targetClass, calledName, 0, visited, cu)); + results.addAll(constantExtractor.resolveMethodReturnConstant( + targetClass, calledName, 0, visited, cu, budget)); } else { String val = constantResolver.resolve(tracedRight, context); if (val != null) results.add(val); @@ -116,7 +117,8 @@ public class ConstructorAnalyzer { } CompilationUnit cu = td.getRoot() instanceof CompilationUnit ? (CompilationUnit) td.getRoot() : null; - results.addAll(constantExtractor.resolveMethodReturnConstant(targetClass, calledName, 0, visited, cu)); + results.addAll(constantExtractor.resolveMethodReturnConstant( + targetClass, calledName, 0, visited, cu, budget)); } else { String val = constantResolver.resolve(tracedRight, context); if (val != null) results.add(val); @@ -164,7 +166,7 @@ public class ConstructorAnalyzer { if (superFqn != null && !superFqn.equals("java.lang.Object")) { TypeDeclaration superTd = context.getTypeDeclaration(superFqn); if (superTd != null) { - results.addAll(traceFieldInConstructors(superTd, fieldName, context, visited, budget)); + results.addAll(traceFieldInConstructors(superTd, fieldName, context, visited, budget.child())); } } } @@ -177,7 +179,7 @@ public class ConstructorAnalyzer { for (String implFqn : impls) { TypeDeclaration implTd = context.getTypeDeclaration(implFqn); if (implTd != null) { - results.addAll(traceFieldInConstructors(implTd, fieldName, context, visited, budget)); + results.addAll(traceFieldInConstructors(implTd, fieldName, context, visited, budget.child())); } } } @@ -189,11 +191,10 @@ public class ConstructorAnalyzer { Collection allTypes = context.getTypeDeclarations(); if (allTypes != null) { int matchedCount = 0; - ResolutionBudget localBudget = ResolutionBudget.defaults(); for (TypeDeclaration typeDecl : allTypes) { if (typeDecl == null) continue; if (context.hasField(typeDecl, fieldName)) { - results.addAll(traceFieldInConstructors(typeDecl, fieldName, context, visited, localBudget)); + results.addAll(traceFieldInConstructors(typeDecl, fieldName, context, visited, budget.child())); matchedCount++; if (matchedCount >= budget.globalFieldScanLimit()) { break; diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/EntryPointBindingExpander.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/EntryPointBindingExpander.java new file mode 100644 index 0000000..54f8f73 --- /dev/null +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/EntryPointBindingExpander.java @@ -0,0 +1,183 @@ +package click.kamil.springstatemachineexporter.analysis.service; + +import click.kamil.springstatemachineexporter.analysis.model.CallEdge; +import click.kamil.springstatemachineexporter.analysis.model.EntryPoint; +import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; +import org.eclipse.jdt.core.dom.*; + +import java.util.*; + +/** + * Expands REST entry points whose {@code @PathVariable} parameters flow into string-keyed + * switch mappers (e.g. {@code StringCommandMapper.fromString}) into concrete binding variants. + */ +public final class EntryPointBindingExpander { + + private EntryPointBindingExpander() { + } + + public static List> expandPathVariableBindings( + EntryPoint entryPoint, + CodebaseContext context, + Map> callGraph) { + if (entryPoint == null || entryPoint.getParameters() == null || entryPoint.getParameters().isEmpty()) { + return List.of(); + } + for (EntryPoint.Parameter parameter : entryPoint.getParameters()) { + if (!isPathOrQueryVariable(parameter)) { + continue; + } + List cases = resolveStringCasesForParameter( + entryPoint.getClassName() + "." + entryPoint.getMethodName(), + parameter.getName(), + context, + callGraph); + if (cases.isEmpty()) { + continue; + } + List> variants = new ArrayList<>(); + for (String caseValue : cases) { + variants.add(Map.of(parameter.getName(), caseValue)); + } + return variants; + } + return List.of(); + } + + public static EntryPoint withResolvedPath(EntryPoint entryPoint, Map bindings) { + if (entryPoint == null || bindings == null || bindings.isEmpty()) { + return entryPoint; + } + String name = entryPoint.getName(); + Map metadata = entryPoint.getMetadata() == null + ? new LinkedHashMap<>() + : new LinkedHashMap<>(entryPoint.getMetadata()); + for (Map.Entry binding : bindings.entrySet()) { + String placeholder = "{" + binding.getKey() + "}"; + if (name != null) { + name = name.replace(placeholder, binding.getValue()); + } + String path = metadata.get("path"); + if (path != null) { + metadata.put("path", path.replace(placeholder, binding.getValue())); + } + } + return EntryPoint.builder() + .type(entryPoint.getType()) + .name(name) + .className(entryPoint.getClassName()) + .methodName(entryPoint.getMethodName()) + .sourceFile(entryPoint.getSourceFile()) + .metadata(metadata) + .parameters(entryPoint.getParameters()) + .build(); + } + + private static boolean isPathOrQueryVariable(EntryPoint.Parameter parameter) { + if (parameter.getAnnotations() == null) { + return false; + } + return parameter.getAnnotations().stream() + .anyMatch(a -> "PathVariable".equals(a) || "RequestParam".equals(a)); + } + + private static List resolveStringCasesForParameter( + String startMethod, + String paramName, + CodebaseContext context, + Map> callGraph) { + ArrayDeque queue = new ArrayDeque<>(); + Set visited = new HashSet<>(); + queue.add(startMethod); + while (!queue.isEmpty()) { + String methodFqn = queue.poll(); + if (!visited.add(methodFqn)) { + continue; + } + if (visited.size() > 12) { + break; + } + List localCases = extractStringSwitchCases(methodFqn, paramName, context); + if (!localCases.isEmpty()) { + return localCases; + } + List edges = callGraph.get(methodFqn); + if (edges == null) { + continue; + } + for (CallEdge edge : edges) { + if (edge.getTargetMethod() != null) { + queue.add(edge.getTargetMethod()); + } + } + } + return List.of(); + } + + static List extractStringSwitchCases(String methodFqn, String paramName, CodebaseContext context) { + MethodDeclaration method = findMethodDeclaration(methodFqn, context); + if (method == null || method.getBody() == null) { + return List.of(); + } + if (!hasParameter(method, paramName)) { + return List.of(); + } + LinkedHashSet cases = new LinkedHashSet<>(); + method.getBody().accept(new ASTVisitor() { + @Override + public boolean visit(SwitchStatement node) { + collectCasesFromSwitch(node.getExpression(), node.statements(), paramName, cases); + return super.visit(node); + } + + @Override + public boolean visit(SwitchExpression node) { + collectCasesFromSwitch(node.getExpression(), node.statements(), paramName, cases); + return super.visit(node); + } + }); + return List.copyOf(cases); + } + + private static void collectCasesFromSwitch( + Expression selector, + List statements, + String paramName, + Set cases) { + if (!(selector instanceof SimpleName simpleName) || !paramName.equals(simpleName.getIdentifier())) { + return; + } + for (Object statementObj : statements) { + if (statementObj instanceof SwitchCase switchCase && !switchCase.isDefault()) { + for (Object exprObj : switchCase.expressions()) { + if (exprObj instanceof StringLiteral stringLiteral) { + cases.add(stringLiteral.getLiteralValue()); + } + } + } + } + } + + private static boolean hasParameter(MethodDeclaration method, String paramName) { + for (Object paramObj : method.parameters()) { + if (paramObj instanceof SingleVariableDeclaration param + && paramName.equals(param.getName().getIdentifier())) { + return true; + } + } + return false; + } + + private static MethodDeclaration findMethodDeclaration(String methodFqn, CodebaseContext context) { + if (methodFqn == null || !methodFqn.contains(".")) { + return null; + } + String className = methodFqn.substring(0, methodFqn.lastIndexOf('.')); + String methodName = methodFqn.substring(methodFqn.lastIndexOf('.') + 1); + TypeDeclaration typeDeclaration = context.getTypeDeclaration(className); + if (typeDeclaration == null) { + return null; + } + return context.findMethodDeclaration(typeDeclaration, methodName, true); + } +} diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/GenericEventDetector.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/GenericEventDetector.java index 924ede1..07b3247 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/GenericEventDetector.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/GenericEventDetector.java @@ -64,7 +64,7 @@ public class GenericEventDetector { } MethodDeclaration method = findEnclosingMethod(node); - TypeDeclaration type = findEnclosingType(node); + AbstractTypeDeclaration type = findEnclosingAbstractType(node); if (type == null) return; String sourceState = extractSourceState(node); @@ -191,18 +191,11 @@ public class GenericEventDetector { if (receiver instanceof SimpleName sn) { String name = sn.getIdentifier(); - // Check if it's a field in the enclosing class - TypeDeclaration td = findEnclosingType(node); - if (td != null) { - for (FieldDeclaration fd : td.getFields()) { - for (Object fragObj : fd.fragments()) { - if (fragObj instanceof VariableDeclarationFragment fragment) { - if (fragment.getName().getIdentifier().equals(name)) { - String typeName = fd.getType().toString(); - return typeName + "." + methodName; - } - } - } + AbstractTypeDeclaration enclosing = findEnclosingAbstractType(node); + if (enclosing != null) { + Type memberType = lookupMemberType(enclosing, name); + if (memberType != null) { + return memberType + "." + methodName; } } return name + "." + methodName; @@ -230,7 +223,7 @@ public class GenericEventDetector { } MethodDeclaration method = findEnclosingMethod(node); - TypeDeclaration type = findEnclosingType(node); + AbstractTypeDeclaration type = findEnclosingAbstractType(node); if (type == null) return Collections.emptyList(); @@ -516,11 +509,49 @@ public class GenericEventDetector { } private TypeDeclaration findEnclosingType(ASTNode node) { + AbstractTypeDeclaration type = findEnclosingAbstractType(node); + return type instanceof TypeDeclaration td ? td : null; + } + + private AbstractTypeDeclaration findEnclosingAbstractType(ASTNode node) { ASTNode parent = node.getParent(); - while (parent != null && !(parent instanceof TypeDeclaration)) { + while (parent != null && !(parent instanceof AbstractTypeDeclaration)) { parent = parent.getParent(); } - return (TypeDeclaration) parent; + return (AbstractTypeDeclaration) parent; + } + + private List getFieldDeclarations(AbstractTypeDeclaration type) { + if (type instanceof TypeDeclaration td) { + return List.of(td.getFields()); + } + if (type instanceof RecordDeclaration rd) { + return List.of(rd.getFields()); + } + return List.of(); + } + + private Type lookupMemberType(AbstractTypeDeclaration enclosingType, String memberName) { + if (enclosingType == null || memberName == null) { + return null; + } + for (FieldDeclaration fd : getFieldDeclarations(enclosingType)) { + for (Object fragObj : fd.fragments()) { + if (fragObj instanceof VariableDeclarationFragment fragment + && fragment.getName().getIdentifier().equals(memberName)) { + return fd.getType(); + } + } + } + if (enclosingType instanceof RecordDeclaration rd) { + for (Object compObj : rd.recordComponents()) { + if (compObj instanceof SingleVariableDeclaration svd + && svd.getName().getIdentifier().equals(memberName)) { + return svd.getType(); + } + } + } + return null; } private String[] resolveStateMachineTypeArguments(MethodInvocation node) { @@ -576,7 +607,7 @@ public class GenericEventDetector { } private String resolveGenericTypeVariable(String typeVarName, ASTNode node, CompilationUnit cu) { - TypeDeclaration enclosingClass = findEnclosingType(node); + AbstractTypeDeclaration enclosingClass = findEnclosingAbstractType(node); if (enclosingClass == null) return typeVarName; String className = context.getFqn(enclosingClass); if (className == null) return typeVarName; @@ -593,7 +624,11 @@ public class GenericEventDetector { String baseName = resolveTypeToFqn(baseType, (CompilationUnit) implNode.getRoot()); if (className.equals(baseName) || className.endsWith("." + baseName)) { int typeIndex = -1; - List typeParams = enclosingClass.typeParameters(); + List typeParams = enclosingClass instanceof TypeDeclaration typeDecl + ? typeDecl.typeParameters() + : enclosingClass instanceof RecordDeclaration recordDecl + ? recordDecl.typeParameters() + : List.of(); for (int i = 0; i < typeParams.size(); i++) { TypeParameter tp = (TypeParameter) typeParams.get(i); if (tp.getName().getIdentifier().equals(typeVarName)) { @@ -665,17 +700,12 @@ public class GenericEventDetector { } } - // Check fields - TypeDeclaration enclosingType = findEnclosingType(node); + // Check fields and record components + AbstractTypeDeclaration enclosingType = findEnclosingAbstractType(node); if (enclosingType != null) { - for (FieldDeclaration fd : enclosingType.getFields()) { - for (Object fragObj : fd.fragments()) { - if (fragObj instanceof VariableDeclarationFragment fragment) { - if (fragment.getName().getIdentifier().equals(varName)) { - return fd.getType(); - } - } - } + Type memberType = lookupMemberType(enclosingType, varName); + if (memberType != null) { + return memberType; } } diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/JdtIntelligenceProvider.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/JdtIntelligenceProvider.java index b381fc9..63e9067 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/JdtIntelligenceProvider.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/JdtIntelligenceProvider.java @@ -97,8 +97,13 @@ public class JdtIntelligenceProvider implements CodebaseIntelligenceProvider { if (cachedCallChains != null) { return cachedCallChains; } - log.info("JdtIntelligenceProvider searching for call chains between {} entry points and {} triggers", entryPoints.size(), triggers.size()); - cachedCallChains = callGraphEngine.findChains(entryPoints, triggers); + List allEntryPoints = findEntryPoints(); + List allTriggers = triggers != null && !triggers.isEmpty() + ? triggers + : findTriggerPoints(); + log.info("JdtIntelligenceProvider searching for call chains between {} entry points and {} triggers", + allEntryPoints.size(), allTriggers.size()); + cachedCallChains = callGraphEngine.findChains(allEntryPoints, allTriggers); return cachedCallChains; } diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/PathBindingEvaluator.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/PathBindingEvaluator.java index 4b5e7cd..6c29533 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/PathBindingEvaluator.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/PathBindingEvaluator.java @@ -50,11 +50,18 @@ public class PathBindingEvaluator { return bindings; } - public boolean isPathCompatible(List path, Map> callGraph, CallGraphPathFinder pathFinder) { + public boolean isPathCompatible( + List path, + Map> callGraph, + CallGraphPathFinder pathFinder, + Map initialBindings) { if (path == null || path.size() < 2) { return true; } Map bindings = new HashMap<>(); + if (initialBindings != null) { + bindings.putAll(initialBindings); + } for (int i = 0; i < path.size() - 1; i++) { String caller = path.get(i); String target = path.get(i + 1); @@ -72,6 +79,10 @@ public class PathBindingEvaluator { return true; } + public boolean isPathCompatible(List path, Map> callGraph, CallGraphPathFinder pathFinder) { + return isPathCompatible(path, callGraph, pathFinder, Map.of()); + } + private void enrichBindings( String caller, String target, diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/ast/common/CodebaseContext.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/ast/common/CodebaseContext.java index 292fb53..55206cd 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/ast/common/CodebaseContext.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/ast/common/CodebaseContext.java @@ -845,8 +845,11 @@ public class CodebaseContext { Type superclass = td.getSuperclassType(); if (superclass != null) { String superclassName = getSimpleName(superclass); - if (knownAdapters.contains(superclassName)) + if (knownAdapters.contains(superclassName) + || superclass.toString().contains("StateMachineConfigurerAdapter") + || superclass.toString().contains("EnumStateMachineConfigurerAdapter")) { return true; + } TypeDeclaration superTd = getTypeDeclaration(superclassName, cu); if (superTd != null && extendsStateMachineConfigurerAdapterLegacy(superTd, visited)) return true; diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/ast/common/JdtDataFlowModel.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/ast/common/JdtDataFlowModel.java index c26b987..df85a97 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/ast/common/JdtDataFlowModel.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/ast/common/JdtDataFlowModel.java @@ -745,38 +745,9 @@ public class JdtDataFlowModel implements DataFlowModel { } private org.eclipse.jdt.core.dom.RecordDeclaration findRecordDeclaration(String fqn) { - for (CompilationUnit cu : context.getCompilationUnits()) { - for (Object typeObj : cu.types()) { - org.eclipse.jdt.core.dom.RecordDeclaration found = findRecordInType(fqn, typeObj); - if (found != null) { - return found; - } - } - } - return null; - } - - private org.eclipse.jdt.core.dom.RecordDeclaration findRecordInType(String fqn, Object typeObj) { - if (typeObj instanceof org.eclipse.jdt.core.dom.RecordDeclaration recordDeclaration) { - if (context.getFqn(recordDeclaration).equals(fqn)) { - return recordDeclaration; - } - for (Object decl : recordDeclaration.bodyDeclarations()) { - if (decl instanceof org.eclipse.jdt.core.dom.RecordDeclaration nested) { - org.eclipse.jdt.core.dom.RecordDeclaration found = findRecordInType(fqn, nested); - if (found != null) { - return found; - } - } - } - } - if (typeObj instanceof TypeDeclaration typeDeclaration) { - for (TypeDeclaration nested : typeDeclaration.getTypes()) { - org.eclipse.jdt.core.dom.RecordDeclaration found = findRecordInType(fqn, nested); - if (found != null) { - return found; - } - } + org.eclipse.jdt.core.dom.AbstractTypeDeclaration abstractType = context.getAbstractTypeDeclaration(fqn); + if (abstractType instanceof org.eclipse.jdt.core.dom.RecordDeclaration recordDeclaration) { + return recordDeclaration; } return null; } diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/enricher/MachineScopeFilterEntryPointTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/enricher/MachineScopeFilterEntryPointTest.java new file mode 100644 index 0000000..1d9a3d0 --- /dev/null +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/enricher/MachineScopeFilterEntryPointTest.java @@ -0,0 +1,48 @@ +package click.kamil.springstatemachineexporter.analysis.enricher; + +import click.kamil.springstatemachineexporter.analysis.model.EntryPoint; +import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class MachineScopeFilterEntryPointTest { + + @Test + void shouldKeepOrderEndpointsOnOrderMachineOnly() { + EntryPoint orderPay = EntryPoint.builder() + .type(EntryPoint.Type.REST) + .name("POST /api/orders/pay") + .className("click.kamil.examples.statemachine.layered.web.OrderController") + .methodName("pay") + .metadata(Map.of("path", "/api/orders/pay")) + .build(); + EntryPoint documentSubmit = EntryPoint.builder() + .type(EntryPoint.Type.REST) + .name("POST /api/documents/submit") + .className("click.kamil.examples.statemachine.layered.web.DocumentController") + .methodName("submit") + .metadata(Map.of("path", "/api/documents/submit")) + .build(); + EntryPoint genericCommand = EntryPoint.builder() + .type(EntryPoint.Type.REST) + .name("POST /api/commands/{commandKey}") + .className("click.kamil.examples.statemachine.layered.web.GenericCommandController") + .methodName("execute") + .metadata(Map.of("path", "/api/commands/{commandKey}")) + .build(); + + CodebaseContext context = new CodebaseContext(); + List orderScoped = MachineScopeFilter.filterEntryPointsForMachine( + List.of(orderPay, documentSubmit, genericCommand), + "click.kamil.examples.statemachine.layered.order.config.StandardOrderStateMachineConfiguration", + context); + + assertThat(orderScoped).extracting(EntryPoint::getName) + .contains("POST /api/orders/pay", "POST /api/commands/{commandKey}") + .doesNotContain("POST /api/documents/submit"); + } +} diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/enricher/routing/HeuristicBeanResolutionEngineTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/enricher/routing/HeuristicBeanResolutionEngineTest.java index 2459f4c..b57478e 100644 --- a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/enricher/routing/HeuristicBeanResolutionEngineTest.java +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/enricher/routing/HeuristicBeanResolutionEngineTest.java @@ -1,9 +1,13 @@ package click.kamil.springstatemachineexporter.analysis.enricher.routing; import click.kamil.springstatemachineexporter.analysis.model.CallChain; +import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import static org.junit.jupiter.api.Assertions.*; @@ -127,4 +131,38 @@ public class HeuristicBeanResolutionEngineTest { boolean result = engine.isRoutedToCorrectMachine(chain, machineName, null); assertTrue(result, "MyStateMachineConfig should not trigger mismatch because it contains StateMachineConfig"); } + + @Test + void shouldRejectAmbiguousChainWhenMultipleStateMachinesExist(@TempDir Path tempDir) throws Exception { + Files.writeString(tempDir.resolve("OrderConfig.java"), """ + package com.example; + @org.springframework.statemachine.config.EnableStateMachine + public class OrderStateMachineConfig + extends org.springframework.statemachine.config.StateMachineConfigurerAdapter {} + enum OrderStates { S1 } + enum OrderEvents { E1 } + """); + Files.writeString(tempDir.resolve("DocumentConfig.java"), """ + package com.example; + @org.springframework.statemachine.config.EnableStateMachine + public class DocumentStateMachineConfig + extends org.springframework.statemachine.config.StateMachineConfigurerAdapter {} + enum DocumentStates { D1 } + enum DocumentEvents { D1E } + """); + + CodebaseContext context = new CodebaseContext(); + context.scan(tempDir); + + CallChain chain = CallChain.builder() + .methodChain(Arrays.asList("com.example.shared.GlobalGateway.fire()")) + .build(); + + assertFalse( + engine.isRoutedToCorrectMachine(chain, "com.example.OrderStateMachineConfig", context), + "Ambiguous shared gateway should not attach to every machine"); + assertFalse( + engine.isRoutedToCorrectMachine(chain, "com.example.DocumentStateMachineConfig", context), + "Ambiguous shared gateway should not attach to every machine"); + } } diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/pipeline/PipelineRefactorTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/pipeline/PipelineRefactorTest.java index e06052d..c2f56b1 100644 --- a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/pipeline/PipelineRefactorTest.java +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/pipeline/PipelineRefactorTest.java @@ -75,8 +75,12 @@ class PipelineRefactorTest { } @Test - void shouldEnableGlobalFieldScanExplicitly() { - assertThat(ResolutionBudget.withGlobalFieldScan().allowGlobalFieldScan()).isTrue(); + void shouldDecrementDepthLimitsViaChild() { + ResolutionBudget child = ResolutionBudget.defaults().child(); + assertThat(child.isMethodReturnExhausted(19)).isFalse(); + assertThat(child.isMethodReturnExhausted(20)).isTrue(); + assertThat(child.isDataflowExhausted(49)).isFalse(); + assertThat(child.isDataflowExhausted(50)).isTrue(); } } diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluatorBindingsTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluatorBindingsTest.java index 00fc97c..a094c59 100644 --- a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluatorBindingsTest.java +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluatorBindingsTest.java @@ -28,4 +28,11 @@ class BooleanConstraintEvaluatorBindingsTest { "commandKey == \"order.pay\"", Map.of("commandKey", "order.pay"))).isTrue(); } + + @Test + void shouldRejectConstraintWhenBindingIsMissing() { + assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings( + "command == ORDER_PAY", + Map.of("commandKey", "order.pay"))).isFalse(); + } } diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/EntryPointBindingExpanderTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/EntryPointBindingExpanderTest.java new file mode 100644 index 0000000..3fbec7f --- /dev/null +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/EntryPointBindingExpanderTest.java @@ -0,0 +1,146 @@ +package click.kamil.springstatemachineexporter.analysis.service; + +import click.kamil.springstatemachineexporter.analysis.model.CallChain; +import click.kamil.springstatemachineexporter.analysis.model.EntryPoint; +import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; +import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class EntryPointBindingExpanderTest { + + @Test + void shouldExpandPathVariableFromStringSwitchMapper(@TempDir Path tempDir) throws Exception { + String source = """ + package com.example; + public class GenericCommandController { + CommandGateway gateway; + public void execute(String commandKey) { + gateway.executeViaMapper(commandKey); + } + } + class CommandGateway { + StringCommandMapper mapper; + void executeViaMapper(String commandKey) { + mapper.fromString(commandKey); + } + } + class StringCommandMapper { + DomainCommand fromString(String commandKey) { + return switch (commandKey) { + case "order.pay" -> DomainCommand.ORDER_PAY; + case "order.ship" -> DomainCommand.ORDER_SHIP; + default -> throw new IllegalArgumentException(commandKey); + }; + } + } + enum DomainCommand { ORDER_PAY, ORDER_SHIP } + """; + Files.writeString(tempDir.resolve("App.java"), source); + + CodebaseContext context = new CodebaseContext(); + context.setResolveBindings(true); + context.scan(tempDir); + + HeuristicCallGraphEngine engine = new HeuristicCallGraphEngine(context); + Map> graph = engine.buildCallGraph(); + + EntryPoint entryPoint = EntryPoint.builder() + .className("com.example.GenericCommandController") + .methodName("execute") + .name("POST /api/commands/{commandKey}") + .parameters(List.of(EntryPoint.Parameter.builder() + .name("commandKey") + .type("String") + .annotations(List.of("PathVariable")) + .build())) + .build(); + + List> variants = + EntryPointBindingExpander.expandPathVariableBindings(entryPoint, context, graph); + + assertThat(variants).extracting(map -> map.get("commandKey")) + .containsExactlyInAnyOrder("order.pay", "order.ship"); + } + + @Test + void shouldProduceSinglePayChainForGenericCommandEndpoint(@TempDir Path tempDir) throws Exception { + String source = """ + package com.example; + public class GenericCommandController { + private final CommandGateway gateway = new CommandGateway(); + public void execute(String commandKey) { + gateway.executeViaMapper(commandKey); + } + } + enum DomainCommand { ORDER_PAY, ORDER_SHIP } + enum OrderEvent { PAY, SHIP } + class CommandGateway { + private final StringCommandMapper mapper = new StringCommandMapper(); + private final CentralDispatcher central = new CentralDispatcher(); + void executeViaMapper(String commandKey) { + DomainCommand command = mapper.fromString(commandKey); + central.dispatch(command); + } + } + class StringCommandMapper { + DomainCommand fromString(String commandKey) { + return switch (commandKey) { + case "order.pay" -> DomainCommand.ORDER_PAY; + case "order.ship" -> DomainCommand.ORDER_SHIP; + default -> throw new IllegalArgumentException(commandKey); + }; + } + } + class CentralDispatcher { + void dispatch(DomainCommand command) { + switch (command) { + case ORDER_PAY -> orderPay(); + case ORDER_SHIP -> orderShip(); + } + } + void orderPay() { fire(OrderEvent.PAY); } + void orderShip() { fire(OrderEvent.SHIP); } + void fire(OrderEvent event) {} + } + """; + Files.writeString(tempDir.resolve("App.java"), source); + + CodebaseContext context = new CodebaseContext(); + context.setResolveBindings(true); + context.scan(tempDir); + + HeuristicCallGraphEngine engine = new HeuristicCallGraphEngine(context); + EntryPoint entryPoint = EntryPoint.builder() + .className("com.example.GenericCommandController") + .methodName("execute") + .name("POST /api/commands/{commandKey}") + .parameters(List.of(EntryPoint.Parameter.builder() + .name("commandKey") + .type("String") + .annotations(List.of("PathVariable")) + .build())) + .build(); + TriggerPoint trigger = TriggerPoint.builder() + .className("com.example.CentralDispatcher") + .methodName("fire") + .event("event") + .build(); + + List chains = engine.findChains(List.of(entryPoint), List.of(trigger)); + + assertThat(chains).hasSize(2); + assertThat(chains.stream().map(chain -> chain.getEntryPoint().getName())) + .containsExactlyInAnyOrder("POST /api/commands/order.pay", "POST /api/commands/order.ship"); + assertThat(chains.stream().filter(chain -> chain.getEntryPoint().getName().endsWith("order.pay"))).hasSize(1); + assertThat(chains.stream().filter(chain -> chain.getEntryPoint().getName().endsWith("order.pay")).findFirst().orElseThrow() + .getMethodChain()).contains("com.example.CentralDispatcher.orderPay"); + } +} diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/GenericEventDetectorRecordTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/GenericEventDetectorRecordTest.java new file mode 100644 index 0000000..14639da --- /dev/null +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/GenericEventDetectorRecordTest.java @@ -0,0 +1,43 @@ +package click.kamil.springstatemachineexporter.analysis.service; + +import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; +import click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver; +import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class GenericEventDetectorRecordTest { + + @Test + void shouldDetectSendEventInsideTopLevelRecord(@TempDir Path tempDir) throws Exception { + Files.writeString(tempDir.resolve("EventBridge.java"), """ + package com.example; + import org.springframework.statemachine.StateMachine; + public record EventBridge(StateMachine sm, String event) { + public void fire() { + sm.sendEvent(event); + } + } + """); + + CodebaseContext context = new CodebaseContext(); + context.setResolveBindings(true); + context.scan(tempDir); + + GenericEventDetector detector = new GenericEventDetector(context, new ConstantResolver(), List.of()); + CompilationUnit cu = context.getCompilationUnits().iterator().next(); + List triggers = detector.detect(cu); + + assertThat(triggers).hasSize(1); + assertThat(triggers.get(0).getClassName()).isEqualTo("com.example.EventBridge"); + assertThat(triggers.get(0).getMethodName()).isEqualTo("fire"); + assertThat(triggers.get(0).getEvent()).isEqualTo("event"); + } +} diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/LayeredDispatcherSampleTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/LayeredDispatcherSampleTest.java index f5ad1eb..f334f80 100644 --- a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/LayeredDispatcherSampleTest.java +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/LayeredDispatcherSampleTest.java @@ -79,6 +79,31 @@ class LayeredDispatcherSampleTest { assertSingleMatchedChain(orderMachine, "POST /api/string-dispatch/orders/ship", "OrderTransitionEvent.SHIP"); } + @Test + void shouldExpandGenericCommandEndpointIntoConcreteKeys(@TempDir Path tempDir) throws Exception { + Path sampleRoot = findProjectRoot().resolve("state_machines/layered_dispatcher_sample"); + ExportService exportService = new ExportService(List.of(new JsonExporter())); + exportService.runExporter(sampleRoot, tempDir, List.of("json"), true, List.of(), null, null, + click.kamil.springstatemachineexporter.exporter.EnumFormat.fn, + click.kamil.springstatemachineexporter.exporter.EnumFormat.fn); + + JsonNode orderMachine = readMachineJson(tempDir, "StandardOrderStateMachineConfiguration", new ObjectMapper()); + + assertEndpointLinksSingleTransition(orderMachine, "POST /api/commands/order.pay", + "OrderTransitionEvent.PAY", "OrderState.NEW", "OrderState.PAID"); + assertEndpointLinksSingleTransition(orderMachine, "POST /api/commands/order.ship", + "OrderTransitionEvent.SHIP", "OrderState.PAID", "OrderState.SHIPPED"); + assertSingleMatchedChain(orderMachine, "POST /api/commands/order.pay", "OrderTransitionEvent.PAY"); + + JsonNode documentMachine = readMachineJson(tempDir, "StandardDocumentStateMachineConfiguration", new ObjectMapper()); + assertEndpointLinksSingleTransition(documentMachine, "POST /api/commands/document.submit", + "DocumentTransitionEvent.SUBMIT", "DocumentState.DRAFT", "DocumentState.SUBMITTED"); + JsonNode entryPoints = documentMachine.path("metadata").path("entryPoints"); + assertThat(entryPoints.isArray()).isTrue(); + assertThat(entryPoints.findValuesAsText("name")) + .noneMatch(name -> name.contains("/api/orders/")); + } + private static void assertSingleMatchedChain(JsonNode machineJson, String endpointName, String expectedEvent) { List matchedChains = findMatchedCallChains(machineJson, endpointName); assertThat(matchedChains).as("matched chains for %s", endpointName).hasSize(1); diff --git a/state_machine_exporter/src/test/resources/golden/EnterpriseStateMachineConfig/EnterpriseStateMachineConfig.json b/state_machine_exporter/src/test/resources/golden/EnterpriseStateMachineConfig/EnterpriseStateMachineConfig.json index 0d7b562..8c7538e 100644 --- a/state_machine_exporter/src/test/resources/golden/EnterpriseStateMachineConfig/EnterpriseStateMachineConfig.json +++ b/state_machine_exporter/src/test/resources/golden/EnterpriseStateMachineConfig/EnterpriseStateMachineConfig.json @@ -80,58 +80,6 @@ "ambiguous" : false } ], "entryPoints" : [ { - "type" : "REST", - "name" : "POST /api/enterprise/orders/place", - "className" : "click.kamil.examples.enterprise.api.OrderApi", - "methodName" : "placeOrder", - "sourceFile" : "src/main/java/click/kamil/examples/enterprise/api/OrderApi.java", - "metadata" : { - "path" : "/api/enterprise/orders/place", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/enterprise/orders/{id}/cancel", - "className" : "click.kamil.examples.enterprise.api.OrderApi", - "methodName" : "cancelOrder", - "sourceFile" : "src/main/java/click/kamil/examples/enterprise/api/OrderApi.java", - "metadata" : { - "path" : "/api/enterprise/orders/{id}/cancel", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "id", - "type" : "String", - "annotations" : [ "PathVariable" ] - } ] - }, { - "type" : "REST", - "name" : "POST /api/enterprise/orders/place", - "className" : "click.kamil.examples.enterprise.api.OrderController", - "methodName" : "placeOrder", - "sourceFile" : "src/main/java/click/kamil/examples/enterprise/api/OrderController.java", - "metadata" : { - "path" : "/api/enterprise/orders/place", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/enterprise/orders/{id}/cancel", - "className" : "click.kamil.examples.enterprise.api.OrderController", - "methodName" : "cancelOrder", - "sourceFile" : "src/main/java/click/kamil/examples/enterprise/api/OrderController.java", - "metadata" : { - "path" : "/api/enterprise/orders/{id}/cancel", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "id", - "type" : "String", - "annotations" : [ "PathVariable" ] - } ] - }, { "type" : "CUSTOM", "name" : "INTERCEPTOR: SecurityInterceptor.preHandle", "className" : "click.kamil.examples.enterprise.api.SecurityInterceptor", diff --git a/state_machine_exporter/src/test/resources/golden/ExtendedStateMachineConfig/ExtendedStateMachineConfig.json b/state_machine_exporter/src/test/resources/golden/ExtendedStateMachineConfig/ExtendedStateMachineConfig.json index b448c4c..c32693d 100644 --- a/state_machine_exporter/src/test/resources/golden/ExtendedStateMachineConfig/ExtendedStateMachineConfig.json +++ b/state_machine_exporter/src/test/resources/golden/ExtendedStateMachineConfig/ExtendedStateMachineConfig.json @@ -1,361 +1,7 @@ { "metadata" : { - "triggers" : [ { - "event" : "FINISH", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "finishOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 34, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "AUDIT_EVENT", - "className" : "click.kamil.examples.statemachine.extended.web.AuditInterceptor", - "methodName" : "preHandle", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/AuditInterceptor.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 16, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "FALLBACK_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.FallbackQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/FallbackQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "PROFILED_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.ProfiledQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/ProfiledQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 19, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "PRIMARY_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.PrimaryQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PrimaryQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 19, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "SUBMIT_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "processSubmit", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 20, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "CANCEL_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "processCancel", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 25, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "[LIFECYCLE:RESTORE]", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "resumeOrder", - "sourceFile" : null, - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 29, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "QUALIFIER_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.QualifierQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/QualifierQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "NAMED_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.NamedQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/NamedQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "AUTHORIZE", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "processPayment", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PaymentServiceImpl.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 22, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "CAPTURE", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "capturePayment", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PaymentServiceImpl.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 35, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "[LIFECYCLE:RESTORE]", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "capturePayment", - "sourceFile" : null, - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 28, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "REACTIVE_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.ReactiveOrderService", - "methodName" : "processReactive", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/ReactiveOrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 18, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - } ], + "triggers" : [ ], "entryPoints" : [ { - "type" : "REST", - "name" : "POST /api/orders/submit", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "submitOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/submit", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/cancel", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "cancelOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/cancel", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/finish", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "finishOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/finish", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/resume", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "resumeOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/resume", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "orderId", - "type" : "String", - "annotations" : [ ] - } ] - }, { - "type" : "REST", - "name" : "POST /api/orders/reactive", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "reactiveOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/reactive", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "orderId", - "type" : "String", - "annotations" : [ ] - } ] - }, { - "type" : "CUSTOM", - "name" : "INTERCEPTOR: AuditInterceptor.preHandle", - "className" : "click.kamil.examples.statemachine.extended.web.AuditInterceptor", - "methodName" : "preHandle", - "sourceFile" : null, - "metadata" : { - "interceptorType" : "Spring MVC Interceptor" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "GET /test-setter", - "className" : "click.kamil.examples.statemachine.extended.web.SetterInjectionController", - "methodName" : "testSetter", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/SetterInjectionController.java", - "metadata" : { - "path" : "/test-setter", - "verb" : "GET" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/quirk/primary", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testPrimary", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/primary", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/quirk/named", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testNamed", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/named", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/quirk/qualifier", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testQualifier", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/qualifier", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/quirk/fallback", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testFallback", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/fallback", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "GET /test-order", - "className" : "click.kamil.examples.statemachine.extended.web.OrderedTestController", - "methodName" : "testOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderedTestController.java", - "metadata" : { - "path" : "/test-order", - "verb" : "GET" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "GET /test-concrete", - "className" : "click.kamil.examples.statemachine.extended.web.ConcreteReturnTypeController", - "methodName" : "testConcrete", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/ConcreteReturnTypeController.java", - "metadata" : { - "path" : "/test-concrete", - "verb" : "GET" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "GET /test-field", - "className" : "click.kamil.examples.statemachine.extended.web.FieldInjectionController", - "methodName" : "testField", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/FieldInjectionController.java", - "metadata" : { - "path" : "/test-field", - "verb" : "GET" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "GET /test-list", - "className" : "click.kamil.examples.statemachine.extended.web.ListInjectionController", - "methodName" : "testList", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/ListInjectionController.java", - "metadata" : { - "path" : "/test-list", - "verb" : "GET" - }, - "parameters" : [ ] - }, { "type" : "REST", "name" : "GET /api/base/{id}", "className" : "click.kamil.examples.statemachine.extended.web.PaymentController", @@ -386,526 +32,7 @@ "annotations" : [ "PathVariable" ] } ] } ], - "callChains" : [ { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/orders/submit", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "submitOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/submit", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.submitOrder", "click.kamil.examples.statemachine.extended.service.OrderService.processSubmit" ], - "triggerPoint" : { - "event" : "SUBMIT_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "processSubmit", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 20, - "polymorphicEvents" : [ "SUBMIT_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : [ { - "sourceState" : "START", - "targetState" : "PROCESSING", - "event" : "SUBMIT_EVENT" - } ] - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/orders/cancel", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "cancelOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/cancel", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.cancelOrder", "click.kamil.examples.statemachine.extended.service.OrderService.processCancel" ], - "triggerPoint" : { - "event" : "CANCEL_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "processCancel", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 25, - "polymorphicEvents" : [ "CANCEL_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : [ { - "sourceState" : "PROCESSING", - "targetState" : "CANCELLED", - "event" : "CANCEL_EVENT" - } ] - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/orders/finish", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "finishOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/finish", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.finishOrder" ], - "triggerPoint" : { - "event" : "FINISH", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "finishOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 34, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : [ { - "sourceState" : "PROCESSING", - "targetState" : "COMPLETED", - "event" : "FINISH" - } ] - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/orders/resume", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "resumeOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/resume", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "orderId", - "type" : "String", - "annotations" : [ ] - } ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.resumeOrder", "click.kamil.examples.statemachine.extended.service.OrderService.resumeOrder" ], - "triggerPoint" : { - "event" : "[LIFECYCLE:RESTORE]", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "resumeOrder", - "sourceFile" : null, - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 29, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : "orderId", - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/orders/reactive", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "reactiveOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/reactive", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "orderId", - "type" : "String", - "annotations" : [ ] - } ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.reactiveOrder", "click.kamil.examples.statemachine.extended.service.ReactiveOrderService.processReactive" ], - "triggerPoint" : { - "event" : "REACTIVE_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.ReactiveOrderService", - "methodName" : "processReactive", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/ReactiveOrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 18, - "polymorphicEvents" : [ "REACTIVE_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : [ { - "sourceState" : "START", - "targetState" : "PROCESSING", - "event" : "REACTIVE_EVENT" - } ] - }, { - "entryPoint" : { - "type" : "CUSTOM", - "name" : "INTERCEPTOR: AuditInterceptor.preHandle", - "className" : "click.kamil.examples.statemachine.extended.web.AuditInterceptor", - "methodName" : "preHandle", - "sourceFile" : null, - "metadata" : { - "interceptorType" : "Spring MVC Interceptor" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.AuditInterceptor.preHandle" ], - "triggerPoint" : { - "event" : "AUDIT_EVENT", - "className" : "click.kamil.examples.statemachine.extended.web.AuditInterceptor", - "methodName" : "preHandle", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/AuditInterceptor.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 16, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : [ { - "sourceState" : "START", - "targetState" : "START", - "event" : "AUDIT_EVENT" - } ] - }, { - "entryPoint" : { - "type" : "REST", - "name" : "GET /test-setter", - "className" : "click.kamil.examples.statemachine.extended.web.SetterInjectionController", - "methodName" : "testSetter", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/SetterInjectionController.java", - "metadata" : { - "path" : "/test-setter", - "verb" : "GET" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.SetterInjectionController.testSetter", "click.kamil.examples.statemachine.extended.service.NamedQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "NAMED_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.NamedQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/NamedQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : [ "NAMED_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/quirk/primary", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testPrimary", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/primary", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.QuirkController.testPrimary", "click.kamil.examples.statemachine.extended.service.PrimaryQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "PRIMARY_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.PrimaryQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PrimaryQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 19, - "polymorphicEvents" : [ "PRIMARY_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/quirk/named", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testNamed", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/named", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.QuirkController.testNamed", "click.kamil.examples.statemachine.extended.service.NamedQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "NAMED_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.NamedQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/NamedQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : [ "NAMED_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/quirk/qualifier", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testQualifier", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/qualifier", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.QuirkController.testQualifier", "click.kamil.examples.statemachine.extended.service.QualifierQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "QUALIFIER_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.QualifierQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/QualifierQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : [ "QUALIFIER_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/quirk/fallback", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testFallback", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/fallback", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.QuirkController.testFallback", "click.kamil.examples.statemachine.extended.service.PrimaryQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "PRIMARY_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.PrimaryQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PrimaryQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 19, - "polymorphicEvents" : [ "PRIMARY_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "GET /test-concrete", - "className" : "click.kamil.examples.statemachine.extended.web.ConcreteReturnTypeController", - "methodName" : "testConcrete", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/ConcreteReturnTypeController.java", - "metadata" : { - "path" : "/test-concrete", - "verb" : "GET" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.ConcreteReturnTypeController.testConcrete", "click.kamil.examples.statemachine.extended.service.QualifierQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "QUALIFIER_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.QualifierQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/QualifierQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : [ "QUALIFIER_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "GET /test-field", - "className" : "click.kamil.examples.statemachine.extended.web.FieldInjectionController", - "methodName" : "testField", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/FieldInjectionController.java", - "metadata" : { - "path" : "/test-field", - "verb" : "GET" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.FieldInjectionController.testField", "click.kamil.examples.statemachine.extended.service.NamedQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "NAMED_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.NamedQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/NamedQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : [ "NAMED_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "GET /api/base/{id}", - "className" : "click.kamil.examples.statemachine.extended.web.PaymentController", - "methodName" : "processBaseEndpoint", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/PaymentController.java", - "metadata" : { - "path" : "/api/base/{id}", - "verb" : "GET" - }, - "parameters" : [ { - "name" : "id", - "type" : "String", - "annotations" : [ "PathVariable" ] - } ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.PaymentController.processBaseEndpoint", "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl.processPayment" ], - "triggerPoint" : { - "event" : "AUTHORIZE", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "processPayment", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PaymentServiceImpl.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 22, - "polymorphicEvents" : [ "AUTHORIZE" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/payment/{id}/capture", - "className" : "click.kamil.examples.statemachine.extended.web.PaymentController", - "methodName" : "capturePaymentEndpoint", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/PaymentController.java", - "metadata" : { - "path" : "/api/payment/{id}/capture", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "id", - "type" : "String", - "annotations" : [ "PathVariable" ] - } ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.PaymentController.capturePaymentEndpoint", "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl.capturePayment" ], - "triggerPoint" : { - "event" : "CAPTURE", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "capturePayment", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PaymentServiceImpl.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 35, - "polymorphicEvents" : [ "CAPTURE" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : "paymentId", - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/payment/{id}/capture", - "className" : "click.kamil.examples.statemachine.extended.web.PaymentController", - "methodName" : "capturePaymentEndpoint", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/PaymentController.java", - "metadata" : { - "path" : "/api/payment/{id}/capture", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "id", - "type" : "String", - "annotations" : [ "PathVariable" ] - } ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.PaymentController.capturePaymentEndpoint", "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl.capturePayment" ], - "triggerPoint" : { - "event" : "[LIFECYCLE:RESTORE]", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "capturePayment", - "sourceFile" : null, - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 28, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : "paymentId", - "matchedTransitions" : null - } ], + "callChains" : [ ], "properties" : { "default" : { "app.states.initial" : "INIT_STATE" diff --git a/state_machine_exporter/src/test/resources/golden/ExtendedStateMachineConfig_PROD/ExtendedStateMachineConfig.json b/state_machine_exporter/src/test/resources/golden/ExtendedStateMachineConfig_PROD/ExtendedStateMachineConfig.json index 9bc40bb..ba097e4 100644 --- a/state_machine_exporter/src/test/resources/golden/ExtendedStateMachineConfig_PROD/ExtendedStateMachineConfig.json +++ b/state_machine_exporter/src/test/resources/golden/ExtendedStateMachineConfig_PROD/ExtendedStateMachineConfig.json @@ -1,361 +1,7 @@ { "metadata" : { - "triggers" : [ { - "event" : "FINISH", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "finishOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 34, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "AUDIT_EVENT", - "className" : "click.kamil.examples.statemachine.extended.web.AuditInterceptor", - "methodName" : "preHandle", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/AuditInterceptor.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 16, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "FALLBACK_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.FallbackQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/FallbackQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "PROFILED_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.ProfiledQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/ProfiledQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 19, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "PRIMARY_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.PrimaryQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PrimaryQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 19, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "SUBMIT_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "processSubmit", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 20, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "CANCEL_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "processCancel", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 25, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "[LIFECYCLE:RESTORE]", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "resumeOrder", - "sourceFile" : null, - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 29, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "QUALIFIER_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.QualifierQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/QualifierQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "NAMED_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.NamedQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/NamedQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "AUTHORIZE", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "processPayment", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PaymentServiceImpl.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 22, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "CAPTURE", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "capturePayment", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PaymentServiceImpl.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 35, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "[LIFECYCLE:RESTORE]", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "capturePayment", - "sourceFile" : null, - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 28, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "REACTIVE_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.ReactiveOrderService", - "methodName" : "processReactive", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/ReactiveOrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 18, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - } ], + "triggers" : [ ], "entryPoints" : [ { - "type" : "REST", - "name" : "POST /api/orders/submit", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "submitOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/submit", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/cancel", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "cancelOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/cancel", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/finish", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "finishOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/finish", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/resume", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "resumeOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/resume", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "orderId", - "type" : "String", - "annotations" : [ ] - } ] - }, { - "type" : "REST", - "name" : "POST /api/orders/reactive", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "reactiveOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/reactive", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "orderId", - "type" : "String", - "annotations" : [ ] - } ] - }, { - "type" : "CUSTOM", - "name" : "INTERCEPTOR: AuditInterceptor.preHandle", - "className" : "click.kamil.examples.statemachine.extended.web.AuditInterceptor", - "methodName" : "preHandle", - "sourceFile" : null, - "metadata" : { - "interceptorType" : "Spring MVC Interceptor" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "GET /test-setter", - "className" : "click.kamil.examples.statemachine.extended.web.SetterInjectionController", - "methodName" : "testSetter", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/SetterInjectionController.java", - "metadata" : { - "path" : "/test-setter", - "verb" : "GET" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/quirk/primary", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testPrimary", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/primary", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/quirk/named", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testNamed", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/named", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/quirk/qualifier", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testQualifier", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/qualifier", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/quirk/fallback", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testFallback", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/fallback", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "GET /test-order", - "className" : "click.kamil.examples.statemachine.extended.web.OrderedTestController", - "methodName" : "testOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderedTestController.java", - "metadata" : { - "path" : "/test-order", - "verb" : "GET" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "GET /test-concrete", - "className" : "click.kamil.examples.statemachine.extended.web.ConcreteReturnTypeController", - "methodName" : "testConcrete", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/ConcreteReturnTypeController.java", - "metadata" : { - "path" : "/test-concrete", - "verb" : "GET" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "GET /test-field", - "className" : "click.kamil.examples.statemachine.extended.web.FieldInjectionController", - "methodName" : "testField", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/FieldInjectionController.java", - "metadata" : { - "path" : "/test-field", - "verb" : "GET" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "GET /test-list", - "className" : "click.kamil.examples.statemachine.extended.web.ListInjectionController", - "methodName" : "testList", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/ListInjectionController.java", - "metadata" : { - "path" : "/test-list", - "verb" : "GET" - }, - "parameters" : [ ] - }, { "type" : "REST", "name" : "GET /api/base/{id}", "className" : "click.kamil.examples.statemachine.extended.web.PaymentController", @@ -386,526 +32,7 @@ "annotations" : [ "PathVariable" ] } ] } ], - "callChains" : [ { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/orders/submit", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "submitOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/submit", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.submitOrder", "click.kamil.examples.statemachine.extended.service.OrderService.processSubmit" ], - "triggerPoint" : { - "event" : "SUBMIT_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "processSubmit", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 20, - "polymorphicEvents" : [ "SUBMIT_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : [ { - "sourceState" : "START", - "targetState" : "PROCESSING", - "event" : "SUBMIT_EVENT" - } ] - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/orders/cancel", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "cancelOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/cancel", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.cancelOrder", "click.kamil.examples.statemachine.extended.service.OrderService.processCancel" ], - "triggerPoint" : { - "event" : "CANCEL_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "processCancel", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 25, - "polymorphicEvents" : [ "CANCEL_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : [ { - "sourceState" : "PROCESSING", - "targetState" : "CANCELLED", - "event" : "CANCEL_EVENT" - } ] - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/orders/finish", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "finishOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/finish", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.finishOrder" ], - "triggerPoint" : { - "event" : "FINISH", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "finishOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 34, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : [ { - "sourceState" : "PROCESSING", - "targetState" : "COMPLETED", - "event" : "FINISH" - } ] - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/orders/resume", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "resumeOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/resume", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "orderId", - "type" : "String", - "annotations" : [ ] - } ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.resumeOrder", "click.kamil.examples.statemachine.extended.service.OrderService.resumeOrder" ], - "triggerPoint" : { - "event" : "[LIFECYCLE:RESTORE]", - "className" : "click.kamil.examples.statemachine.extended.service.OrderService", - "methodName" : "resumeOrder", - "sourceFile" : null, - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 29, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : "orderId", - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/orders/reactive", - "className" : "click.kamil.examples.statemachine.extended.web.OrderController", - "methodName" : "reactiveOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/reactive", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "orderId", - "type" : "String", - "annotations" : [ ] - } ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.reactiveOrder", "click.kamil.examples.statemachine.extended.service.ReactiveOrderService.processReactive" ], - "triggerPoint" : { - "event" : "REACTIVE_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.ReactiveOrderService", - "methodName" : "processReactive", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/ReactiveOrderService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 18, - "polymorphicEvents" : [ "REACTIVE_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : [ { - "sourceState" : "START", - "targetState" : "PROCESSING", - "event" : "REACTIVE_EVENT" - } ] - }, { - "entryPoint" : { - "type" : "CUSTOM", - "name" : "INTERCEPTOR: AuditInterceptor.preHandle", - "className" : "click.kamil.examples.statemachine.extended.web.AuditInterceptor", - "methodName" : "preHandle", - "sourceFile" : null, - "metadata" : { - "interceptorType" : "Spring MVC Interceptor" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.AuditInterceptor.preHandle" ], - "triggerPoint" : { - "event" : "AUDIT_EVENT", - "className" : "click.kamil.examples.statemachine.extended.web.AuditInterceptor", - "methodName" : "preHandle", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/AuditInterceptor.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 16, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : [ { - "sourceState" : "START", - "targetState" : "START", - "event" : "AUDIT_EVENT" - } ] - }, { - "entryPoint" : { - "type" : "REST", - "name" : "GET /test-setter", - "className" : "click.kamil.examples.statemachine.extended.web.SetterInjectionController", - "methodName" : "testSetter", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/SetterInjectionController.java", - "metadata" : { - "path" : "/test-setter", - "verb" : "GET" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.SetterInjectionController.testSetter", "click.kamil.examples.statemachine.extended.service.NamedQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "NAMED_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.NamedQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/NamedQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : [ "NAMED_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/quirk/primary", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testPrimary", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/primary", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.QuirkController.testPrimary", "click.kamil.examples.statemachine.extended.service.PrimaryQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "PRIMARY_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.PrimaryQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PrimaryQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 19, - "polymorphicEvents" : [ "PRIMARY_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/quirk/named", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testNamed", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/named", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.QuirkController.testNamed", "click.kamil.examples.statemachine.extended.service.NamedQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "NAMED_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.NamedQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/NamedQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : [ "NAMED_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/quirk/qualifier", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testQualifier", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/qualifier", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.QuirkController.testQualifier", "click.kamil.examples.statemachine.extended.service.QualifierQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "QUALIFIER_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.QualifierQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/QualifierQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : [ "QUALIFIER_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/quirk/fallback", - "className" : "click.kamil.examples.statemachine.extended.web.QuirkController", - "methodName" : "testFallback", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/QuirkController.java", - "metadata" : { - "path" : "/api/quirk/fallback", - "verb" : "POST" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.QuirkController.testFallback", "click.kamil.examples.statemachine.extended.service.PrimaryQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "PRIMARY_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.PrimaryQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PrimaryQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 19, - "polymorphicEvents" : [ "PRIMARY_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "GET /test-concrete", - "className" : "click.kamil.examples.statemachine.extended.web.ConcreteReturnTypeController", - "methodName" : "testConcrete", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/ConcreteReturnTypeController.java", - "metadata" : { - "path" : "/test-concrete", - "verb" : "GET" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.ConcreteReturnTypeController.testConcrete", "click.kamil.examples.statemachine.extended.service.QualifierQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "QUALIFIER_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.QualifierQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/QualifierQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : [ "QUALIFIER_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "GET /test-field", - "className" : "click.kamil.examples.statemachine.extended.web.FieldInjectionController", - "methodName" : "testField", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/FieldInjectionController.java", - "metadata" : { - "path" : "/test-field", - "verb" : "GET" - }, - "parameters" : [ ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.FieldInjectionController.testField", "click.kamil.examples.statemachine.extended.service.NamedQuirkService.doQuirk" ], - "triggerPoint" : { - "event" : "NAMED_EVENT", - "className" : "click.kamil.examples.statemachine.extended.service.NamedQuirkService", - "methodName" : "doQuirk", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/NamedQuirkService.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 17, - "polymorphicEvents" : [ "NAMED_EVENT" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "GET /api/base/{id}", - "className" : "click.kamil.examples.statemachine.extended.web.PaymentController", - "methodName" : "processBaseEndpoint", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/PaymentController.java", - "metadata" : { - "path" : "/api/base/{id}", - "verb" : "GET" - }, - "parameters" : [ { - "name" : "id", - "type" : "String", - "annotations" : [ "PathVariable" ] - } ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.PaymentController.processBaseEndpoint", "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl.processPayment" ], - "triggerPoint" : { - "event" : "AUTHORIZE", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "processPayment", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PaymentServiceImpl.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 22, - "polymorphicEvents" : [ "AUTHORIZE" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : null, - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/payment/{id}/capture", - "className" : "click.kamil.examples.statemachine.extended.web.PaymentController", - "methodName" : "capturePaymentEndpoint", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/PaymentController.java", - "metadata" : { - "path" : "/api/payment/{id}/capture", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "id", - "type" : "String", - "annotations" : [ "PathVariable" ] - } ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.PaymentController.capturePaymentEndpoint", "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl.capturePayment" ], - "triggerPoint" : { - "event" : "CAPTURE", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "capturePayment", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/PaymentServiceImpl.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 35, - "polymorphicEvents" : [ "CAPTURE" ], - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : "paymentId", - "matchedTransitions" : null - }, { - "entryPoint" : { - "type" : "REST", - "name" : "POST /api/payment/{id}/capture", - "className" : "click.kamil.examples.statemachine.extended.web.PaymentController", - "methodName" : "capturePaymentEndpoint", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/PaymentController.java", - "metadata" : { - "path" : "/api/payment/{id}/capture", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "id", - "type" : "String", - "annotations" : [ "PathVariable" ] - } ] - }, - "methodChain" : [ "click.kamil.examples.statemachine.extended.web.PaymentController.capturePaymentEndpoint", "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl.capturePayment" ], - "triggerPoint" : { - "event" : "[LIFECYCLE:RESTORE]", - "className" : "click.kamil.examples.statemachine.extended.service.PaymentServiceImpl", - "methodName" : "capturePayment", - "sourceFile" : null, - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 28, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, - "contextMachineId" : "paymentId", - "matchedTransitions" : null - } ], + "callChains" : [ ], "properties" : { "default" : { "app.states.initial" : "INIT_STATE" diff --git a/state_machine_exporter/src/test/resources/golden/InheritanceStateMachineConfig/InheritanceStateMachineConfig.json b/state_machine_exporter/src/test/resources/golden/InheritanceStateMachineConfig/InheritanceStateMachineConfig.json index 3a93e6f..58748dd 100644 --- a/state_machine_exporter/src/test/resources/golden/InheritanceStateMachineConfig/InheritanceStateMachineConfig.json +++ b/state_machine_exporter/src/test/resources/golden/InheritanceStateMachineConfig/InheritanceStateMachineConfig.json @@ -14,29 +14,7 @@ "constraint" : null, "ambiguous" : false } ], - "entryPoints" : [ { - "type" : "REST", - "name" : "POST /api/v2/orders/submit", - "className" : "click.kamil.examples.statemachine.inheritance.api.OrderApi", - "methodName" : "submitOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/inheritance/api/OrderApi.java", - "metadata" : { - "path" : "/api/v2/orders/submit", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/v2/orders/submit", - "className" : "click.kamil.examples.statemachine.inheritance.api.OrderControllerImpl", - "methodName" : "submitOrder", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/inheritance/api/OrderControllerImpl.java", - "metadata" : { - "path" : "/api/v2/orders/submit", - "verb" : "POST" - }, - "parameters" : [ ] - } ], + "entryPoints" : [ ], "callChains" : [ { "entryPoint" : { "type" : "REST", diff --git a/state_machine_exporter/src/test/resources/golden/MavenOrderStateMachine/MavenOrderStateMachine.json b/state_machine_exporter/src/test/resources/golden/MavenOrderStateMachine/MavenOrderStateMachine.json index 4b8aa12..dc6206c 100644 --- a/state_machine_exporter/src/test/resources/golden/MavenOrderStateMachine/MavenOrderStateMachine.json +++ b/state_machine_exporter/src/test/resources/golden/MavenOrderStateMachine/MavenOrderStateMachine.json @@ -1,90 +1,7 @@ { "metadata" : { - "triggers" : [ { - "event" : "SUBMIT", - "className" : "click.kamil.maven.core.MavenOrderStateMachine.OrderController", - "methodName" : "submitOrder", - "sourceFile" : "core-module/src/main/java/click/kamil/maven/core/MavenOrderStateMachine.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 40, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - }, { - "event" : "ORDER_EVENT", - "className" : "click.kamil.maven.core.MavenOrderStateMachine.OrderService", - "methodName" : "onMessage", - "sourceFile" : "core-module/src/main/java/click/kamil/maven/core/MavenOrderStateMachine.java", - "sourceModule" : null, - "stateMachineId" : null, - "sourceState" : null, - "lineNumber" : 52, - "polymorphicEvents" : null, - "external" : false, - "constraint" : null, - "ambiguous" : false - } ], - "entryPoints" : [ { - "type" : "REST", - "name" : "POST /maven/orders/submit", - "className" : "click.kamil.maven.core.MavenOrderStateMachine.OrderController", - "methodName" : "submitOrder", - "sourceFile" : "core-module/src/main/java/click/kamil/maven/core/MavenOrderStateMachine.java", - "metadata" : { - "path" : "/maven/orders/submit", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "orderId", - "type" : "String", - "annotations" : [ "RequestBody" ] - } ] - }, { - "type" : "REST", - "name" : "POST /reactive/order", - "className" : "click.kamil.maven.api.ReactiveOrderApi", - "methodName" : "orderRoutes", - "sourceFile" : "api-module/src/main/java/click/kamil/maven/api/ReactiveOrderApi.java", - "metadata" : { - "path" : "/reactive/order", - "verb" : "POST", - "style" : "WebFlux Functional" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /maven/orders/submit", - "className" : "click.kamil.maven.api.MavenOrderApi", - "methodName" : "submitOrder", - "sourceFile" : "api-module/src/main/java/click/kamil/maven/api/MavenOrderApi.java", - "metadata" : { - "path" : "/maven/orders/submit", - "verb" : "POST" - }, - "parameters" : [ { - "name" : "orderId", - "type" : "String", - "annotations" : [ "RequestBody" ] - } ] - }, { - "type" : "JMS", - "name" : "JMS: order.queue", - "className" : "click.kamil.maven.api.JmsOrderListener", - "methodName" : "onMessage", - "sourceFile" : "api-module/src/main/java/click/kamil/maven/api/JmsOrderListener.java", - "metadata" : { - "protocol" : "JMS", - "destination" : "order.queue" - }, - "parameters" : [ { - "name" : "message", - "type" : "String", - "annotations" : [ ] - } ] - } ], + "triggers" : [ ], + "entryPoints" : [ ], "callChains" : [ { "entryPoint" : { "type" : "REST", diff --git a/state_machine_exporter/src/test/resources/golden/StandardDocumentStateMachineConfiguration/StandardDocumentStateMachineConfiguration.json b/state_machine_exporter/src/test/resources/golden/StandardDocumentStateMachineConfiguration/StandardDocumentStateMachineConfiguration.json index 85139c4..f80bf43 100644 --- a/state_machine_exporter/src/test/resources/golden/StandardDocumentStateMachineConfiguration/StandardDocumentStateMachineConfiguration.json +++ b/state_machine_exporter/src/test/resources/golden/StandardDocumentStateMachineConfiguration/StandardDocumentStateMachineConfiguration.json @@ -15,116 +15,6 @@ "ambiguous" : false } ], "entryPoints" : [ { - "type" : "REST", - "name" : "POST /api/orders/pay", - "className" : "click.kamil.examples.statemachine.layered.web.OrderController", - "methodName" : "pay", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/pay", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/ship", - "className" : "click.kamil.examples.statemachine.layered.web.OrderController", - "methodName" : "ship", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/ship", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/cancel", - "className" : "click.kamil.examples.statemachine.layered.web.OrderController", - "methodName" : "cancel", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/cancel", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/documents/submit", - "className" : "click.kamil.examples.statemachine.layered.web.DocumentController", - "methodName" : "submit", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/DocumentController.java", - "metadata" : { - "path" : "/api/documents/submit", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/documents/approve", - "className" : "click.kamil.examples.statemachine.layered.web.DocumentController", - "methodName" : "approve", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/DocumentController.java", - "metadata" : { - "path" : "/api/documents/approve", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/documents/reject", - "className" : "click.kamil.examples.statemachine.layered.web.DocumentController", - "methodName" : "reject", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/DocumentController.java", - "metadata" : { - "path" : "/api/documents/reject", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/string-dispatch/orders/pay", - "className" : "click.kamil.examples.statemachine.layered.web.StringDispatchController", - "methodName" : "payWithStringKey", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/StringDispatchController.java", - "metadata" : { - "path" : "/api/string-dispatch/orders/pay", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/string-dispatch/orders/ship", - "className" : "click.kamil.examples.statemachine.layered.web.StringDispatchController", - "methodName" : "shipWithStringKey", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/StringDispatchController.java", - "metadata" : { - "path" : "/api/string-dispatch/orders/ship", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/rich/pay", - "className" : "click.kamil.examples.statemachine.layered.web.RichOrderController", - "methodName" : "payViaRichEvent", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/RichOrderController.java", - "metadata" : { - "path" : "/api/orders/rich/pay", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/rich/ship", - "className" : "click.kamil.examples.statemachine.layered.web.RichOrderController", - "methodName" : "shipViaRichEvent", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/RichOrderController.java", - "metadata" : { - "path" : "/api/orders/rich/ship", - "verb" : "POST" - }, - "parameters" : [ ] - }, { "type" : "REST", "name" : "POST /api/commands/{commandKey}", "className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController", @@ -245,12 +135,12 @@ }, { "entryPoint" : { "type" : "REST", - "name" : "POST /api/commands/{commandKey}", + "name" : "POST /api/commands/document.submit", "className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController", "methodName" : "execute", "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java", "metadata" : { - "path" : "/api/commands/{commandKey}", + "path" : "/api/commands/document.submit", "verb" : "POST" }, "parameters" : [ { @@ -283,12 +173,12 @@ }, { "entryPoint" : { "type" : "REST", - "name" : "POST /api/commands/{commandKey}", + "name" : "POST /api/commands/document.approve", "className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController", "methodName" : "execute", "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java", "metadata" : { - "path" : "/api/commands/{commandKey}", + "path" : "/api/commands/document.approve", "verb" : "POST" }, "parameters" : [ { @@ -321,12 +211,12 @@ }, { "entryPoint" : { "type" : "REST", - "name" : "POST /api/commands/{commandKey}", + "name" : "POST /api/commands/document.reject", "className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController", "methodName" : "execute", "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java", "metadata" : { - "path" : "/api/commands/{commandKey}", + "path" : "/api/commands/document.reject", "verb" : "POST" }, "parameters" : [ { diff --git a/state_machine_exporter/src/test/resources/golden/StandardOrderStateMachineConfiguration/StandardOrderStateMachineConfiguration.json b/state_machine_exporter/src/test/resources/golden/StandardOrderStateMachineConfiguration/StandardOrderStateMachineConfiguration.json index 1ef9a92..d206b2a 100644 --- a/state_machine_exporter/src/test/resources/golden/StandardOrderStateMachineConfiguration/StandardOrderStateMachineConfiguration.json +++ b/state_machine_exporter/src/test/resources/golden/StandardOrderStateMachineConfiguration/StandardOrderStateMachineConfiguration.json @@ -15,116 +15,6 @@ "ambiguous" : false } ], "entryPoints" : [ { - "type" : "REST", - "name" : "POST /api/orders/pay", - "className" : "click.kamil.examples.statemachine.layered.web.OrderController", - "methodName" : "pay", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/pay", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/ship", - "className" : "click.kamil.examples.statemachine.layered.web.OrderController", - "methodName" : "ship", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/ship", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/cancel", - "className" : "click.kamil.examples.statemachine.layered.web.OrderController", - "methodName" : "cancel", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/cancel", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/documents/submit", - "className" : "click.kamil.examples.statemachine.layered.web.DocumentController", - "methodName" : "submit", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/DocumentController.java", - "metadata" : { - "path" : "/api/documents/submit", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/documents/approve", - "className" : "click.kamil.examples.statemachine.layered.web.DocumentController", - "methodName" : "approve", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/DocumentController.java", - "metadata" : { - "path" : "/api/documents/approve", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/documents/reject", - "className" : "click.kamil.examples.statemachine.layered.web.DocumentController", - "methodName" : "reject", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/DocumentController.java", - "metadata" : { - "path" : "/api/documents/reject", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/string-dispatch/orders/pay", - "className" : "click.kamil.examples.statemachine.layered.web.StringDispatchController", - "methodName" : "payWithStringKey", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/StringDispatchController.java", - "metadata" : { - "path" : "/api/string-dispatch/orders/pay", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/string-dispatch/orders/ship", - "className" : "click.kamil.examples.statemachine.layered.web.StringDispatchController", - "methodName" : "shipWithStringKey", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/StringDispatchController.java", - "metadata" : { - "path" : "/api/string-dispatch/orders/ship", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/rich/pay", - "className" : "click.kamil.examples.statemachine.layered.web.RichOrderController", - "methodName" : "payViaRichEvent", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/RichOrderController.java", - "metadata" : { - "path" : "/api/orders/rich/pay", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/rich/ship", - "className" : "click.kamil.examples.statemachine.layered.web.RichOrderController", - "methodName" : "shipViaRichEvent", - "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/RichOrderController.java", - "metadata" : { - "path" : "/api/orders/rich/ship", - "verb" : "POST" - }, - "parameters" : [ ] - }, { "type" : "REST", "name" : "POST /api/commands/{commandKey}", "className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController", @@ -381,12 +271,12 @@ }, { "entryPoint" : { "type" : "REST", - "name" : "POST /api/commands/{commandKey}", + "name" : "POST /api/commands/order.pay", "className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController", "methodName" : "execute", "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java", "metadata" : { - "path" : "/api/commands/{commandKey}", + "path" : "/api/commands/order.pay", "verb" : "POST" }, "parameters" : [ { @@ -419,12 +309,12 @@ }, { "entryPoint" : { "type" : "REST", - "name" : "POST /api/commands/{commandKey}", + "name" : "POST /api/commands/order.ship", "className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController", "methodName" : "execute", "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java", "metadata" : { - "path" : "/api/commands/{commandKey}", + "path" : "/api/commands/order.ship", "verb" : "POST" }, "parameters" : [ { @@ -457,12 +347,12 @@ }, { "entryPoint" : { "type" : "REST", - "name" : "POST /api/commands/{commandKey}", + "name" : "POST /api/commands/order.cancel", "className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController", "methodName" : "execute", "sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java", "metadata" : { - "path" : "/api/commands/{commandKey}", + "path" : "/api/commands/order.cancel", "verb" : "POST" }, "parameters" : [ { diff --git a/state_machine_exporter/src/test/resources/golden/StateMachineConfig/StateMachineConfig.json b/state_machine_exporter/src/test/resources/golden/StateMachineConfig/StateMachineConfig.json index 11b410c..3d5d9d1 100644 --- a/state_machine_exporter/src/test/resources/golden/StateMachineConfig/StateMachineConfig.json +++ b/state_machine_exporter/src/test/resources/golden/StateMachineConfig/StateMachineConfig.json @@ -41,50 +41,6 @@ "ambiguous" : false } ], "entryPoints" : [ { - "type" : "REST", - "name" : "POST /api/orders/process", - "className" : "click.kamil.web.OrderController", - "methodName" : "processOrder", - "sourceFile" : "web/src/main/java/click/kamil/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/process", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/complete", - "className" : "click.kamil.web.OrderController", - "methodName" : "completeOrder", - "sourceFile" : "web/src/main/java/click/kamil/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/complete", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/cancel", - "className" : "click.kamil.web.OrderController", - "methodName" : "cancelOrder", - "sourceFile" : "web/src/main/java/click/kamil/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/cancel", - "verb" : "POST" - }, - "parameters" : [ ] - }, { - "type" : "REST", - "name" : "POST /api/orders/functional-complete", - "className" : "click.kamil.web.OrderController", - "methodName" : "functionalCompleteOrder", - "sourceFile" : "web/src/main/java/click/kamil/web/OrderController.java", - "metadata" : { - "path" : "/api/orders/functional-complete", - "verb" : "POST" - }, - "parameters" : [ ] - }, { "type" : "RABBIT", "name" : "RABBIT: order.custom.transition.queue", "className" : "click.kamil.web.RabbitOrderListener",