Compare commits
1 Commits
working_bu
...
29e391c472
| Author | SHA1 | Date | |
|---|---|---|---|
| 29e391c472 |
@@ -12,24 +12,16 @@ public class HeuristicEventMatchingEngine implements EventMatchingEngine {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String rawTriggerEvent = triggerPoint.getEvent();
|
String triggerEvent = simplify(triggerPoint.getEvent());
|
||||||
String smEventRaw = stateMachineEvent.fullIdentifier() != null ? stateMachineEvent.fullIdentifier() : stateMachineEvent.rawName();
|
String smEventRaw = stateMachineEvent.fullIdentifier() != null ? stateMachineEvent.fullIdentifier() : stateMachineEvent.rawName();
|
||||||
String smEvent = simplify(smEventRaw);
|
String smEvent = simplify(smEventRaw);
|
||||||
|
|
||||||
boolean isWildcard = isWildcardVariable(rawTriggerEvent);
|
boolean isWildcard = isWildcardVariable(triggerEvent);
|
||||||
|
|
||||||
List<String> polyEvents = triggerPoint.getPolymorphicEvents() != null ? triggerPoint.getPolymorphicEvents() : java.util.Collections.emptyList();
|
List<String> polyEvents = triggerPoint.getPolymorphicEvents() != null ? triggerPoint.getPolymorphicEvents() : java.util.Collections.emptyList();
|
||||||
|
|
||||||
boolean hasPolyMatch = false;
|
boolean hasPolyMatch = false;
|
||||||
for (String pe : polyEvents) {
|
for (String pe : polyEvents) {
|
||||||
if (pe.contains(".") && smEventRaw.contains(".")) {
|
|
||||||
if (smEventRaw.equals(pe) || smEventRaw.endsWith("." + pe)) {
|
|
||||||
hasPolyMatch = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue; // Stricter matching: do not fallback if both have qualifiers but don't match
|
|
||||||
}
|
|
||||||
|
|
||||||
String simplePe = pe;
|
String simplePe = pe;
|
||||||
if (pe.contains(".")) {
|
if (pe.contains(".")) {
|
||||||
simplePe = pe.substring(pe.lastIndexOf('.') + 1);
|
simplePe = pe.substring(pe.lastIndexOf('.') + 1);
|
||||||
@@ -43,18 +35,7 @@ public class HeuristicEventMatchingEngine implements EventMatchingEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasPolyMatch) return true;
|
return hasPolyMatch || smEvent.equals(triggerEvent) || (polyEvents.isEmpty() && isWildcard);
|
||||||
if (polyEvents.isEmpty() && isWildcard) return true;
|
|
||||||
|
|
||||||
if (rawTriggerEvent.contains(".") && smEventRaw.contains(".")) {
|
|
||||||
if (smEventRaw.equals(rawTriggerEvent) || smEventRaw.endsWith("." + rawTriggerEvent)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String triggerEvent = simplify(rawTriggerEvent);
|
|
||||||
return smEvent.equals(triggerEvent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isWildcardVariable(String eventStr) {
|
private boolean isWildcardVariable(String eventStr) {
|
||||||
|
|||||||
@@ -17,19 +17,6 @@ public class ConstantResolver {
|
|||||||
private String resolveInternal(Expression expr, CodebaseContext context, Set<String> visited) {
|
private String resolveInternal(Expression expr, CodebaseContext context, Set<String> visited) {
|
||||||
if (expr == null) return null;
|
if (expr == null) return null;
|
||||||
|
|
||||||
// Unwrap common wrappers
|
|
||||||
if (expr instanceof CastExpression ce) {
|
|
||||||
return resolveInternal(ce.getExpression(), context, visited);
|
|
||||||
}
|
|
||||||
if (expr instanceof ParenthesizedExpression pe) {
|
|
||||||
return resolveInternal(pe.getExpression(), context, visited);
|
|
||||||
}
|
|
||||||
if (expr instanceof MethodInvocation mi && (mi.getName().getIdentifier().equals("requireNonNull") || mi.getName().getIdentifier().equals("notNull"))) {
|
|
||||||
if (!mi.arguments().isEmpty()) {
|
|
||||||
return resolveInternal((Expression) mi.arguments().get(0), context, visited);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. Literal?
|
// 1. Literal?
|
||||||
if (expr instanceof StringLiteral sl) {
|
if (expr instanceof StringLiteral sl) {
|
||||||
return sl.getLiteralValue();
|
return sl.getLiteralValue();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -12,15 +12,565 @@ import org.eclipse.jdt.core.dom.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
public class HeuristicCallGraphEngine implements CallGraphEngine {
|
||||||
protected String currentMethodFqn;
|
private final CodebaseContext context;
|
||||||
protected Map<String, List<CallEdge>> graph;
|
private final ConstantResolver constantResolver;
|
||||||
|
private String currentMethodFqn;
|
||||||
|
private Map<String, List<CallEdge>> graph;
|
||||||
|
|
||||||
public HeuristicCallGraphEngine(CodebaseContext context) {
|
public HeuristicCallGraphEngine(CodebaseContext context) {
|
||||||
super(context);
|
this.context = context;
|
||||||
|
this.constantResolver = new ConstantResolver();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, List<CallEdge>> buildCallGraph() {
|
public List<CallChain> findChains(List<EntryPoint> entryPoints, List<TriggerPoint> triggers) {
|
||||||
|
Map<String, List<CallEdge>> callGraph = buildCallGraph();
|
||||||
|
List<CallChain> chains = new ArrayList<>();
|
||||||
|
|
||||||
|
for (EntryPoint ep : entryPoints) {
|
||||||
|
String startMethod = ep.getClassName() + "." + ep.getMethodName();
|
||||||
|
boolean foundAny = false;
|
||||||
|
for (TriggerPoint tp : triggers) {
|
||||||
|
String targetMethod = tp.getClassName() + "." + tp.getMethodName();
|
||||||
|
List<String> path = findPath(startMethod, targetMethod, callGraph, new HashSet<>());
|
||||||
|
if (path != null) {
|
||||||
|
foundAny = true;
|
||||||
|
TriggerPoint resolvedTp = resolveTriggerPointParameters(tp, path, callGraph);
|
||||||
|
String contextMachineId = extractContextMachineId(path, callGraph);
|
||||||
|
chains.add(CallChain.builder()
|
||||||
|
.entryPoint(ep)
|
||||||
|
.triggerPoint(resolvedTp)
|
||||||
|
.methodChain(path)
|
||||||
|
.contextMachineId(contextMachineId)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundAny && log.isDebugEnabled()) {
|
||||||
|
log.debug("Entry point {} ({}) did not reach any trigger points. Graph nodes available: {}", ep.getName(), startMethod, callGraph.keySet());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chains;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TriggerPoint resolveTriggerPointParameters(TriggerPoint tp, List<String> path, Map<String, List<CallEdge>> callGraph) {
|
||||||
|
if (path.size() < 2) return tp;
|
||||||
|
|
||||||
|
String event = tp.getEvent();
|
||||||
|
if (event == null || event.isEmpty() || event.contains("\"")) return tp;
|
||||||
|
|
||||||
|
String currentParamName = event;
|
||||||
|
String resolvedValue = event;
|
||||||
|
String methodSuffix = "";
|
||||||
|
|
||||||
|
// Extract method calls like .getType() so we can trace the base parameter
|
||||||
|
int dotIndex = currentParamName.indexOf('.');
|
||||||
|
if (dotIndex > 0 && dotIndex + 1 < currentParamName.length()) {
|
||||||
|
char nextChar = currentParamName.charAt(dotIndex + 1);
|
||||||
|
if (Character.isLowerCase(nextChar)) {
|
||||||
|
methodSuffix = currentParamName.substring(dotIndex);
|
||||||
|
currentParamName = currentParamName.substring(0, dotIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk backwards up the call chain
|
||||||
|
for (int i = path.size() - 1; i > 0; i--) {
|
||||||
|
String target = path.get(i);
|
||||||
|
String caller = path.get(i - 1);
|
||||||
|
|
||||||
|
// Find parameter index in target method
|
||||||
|
int paramIndex = getParameterIndex(target, currentParamName);
|
||||||
|
if (paramIndex < 0) {
|
||||||
|
// Not a parameter. Maybe it's a local variable initialized from a parameter or method call?
|
||||||
|
String tracedVar = traceLocalVariable(target, currentParamName);
|
||||||
|
if (tracedVar != null && !tracedVar.equals(currentParamName)) {
|
||||||
|
// Extract method calls like .getType() from the traced variable
|
||||||
|
int dotIdx = tracedVar.indexOf('.');
|
||||||
|
if (dotIdx > 0 && dotIdx + 1 < tracedVar.length() && Character.isLowerCase(tracedVar.charAt(dotIdx + 1))) {
|
||||||
|
methodSuffix = tracedVar.substring(dotIdx) + methodSuffix;
|
||||||
|
tracedVar = tracedVar.substring(0, dotIdx);
|
||||||
|
}
|
||||||
|
currentParamName = tracedVar;
|
||||||
|
resolvedValue = tracedVar + methodSuffix;
|
||||||
|
paramIndex = getParameterIndex(target, currentParamName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (paramIndex < 0) {
|
||||||
|
break; // Parameter name changed or not found, stop tracing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the edge from caller to target to get the argument passed
|
||||||
|
List<CallEdge> edges = callGraph.get(caller);
|
||||||
|
boolean found = false;
|
||||||
|
if (edges != null) {
|
||||||
|
for (CallEdge edge : edges) {
|
||||||
|
if (edge.getTargetMethod().equals(target) || isHeuristicMatch(edge.getTargetMethod(), target)) {
|
||||||
|
if (paramIndex < edge.getArguments().size()) {
|
||||||
|
String arg = edge.getArguments().get(paramIndex);
|
||||||
|
if (arg != null) {
|
||||||
|
// If the argument passed has a method call, extract it
|
||||||
|
int dotIdx = arg.indexOf('.');
|
||||||
|
if (dotIdx > 0 && dotIdx + 1 < arg.length() && Character.isLowerCase(arg.charAt(dotIdx + 1))) {
|
||||||
|
methodSuffix = arg.substring(dotIdx) + methodSuffix;
|
||||||
|
arg = arg.substring(0, dotIdx);
|
||||||
|
}
|
||||||
|
currentParamName = arg;
|
||||||
|
resolvedValue = arg + methodSuffix;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) break; // Could not map argument
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final check on the entry method
|
||||||
|
String entryMethod = path.get(0);
|
||||||
|
int entryParamIndex = getParameterIndex(entryMethod, currentParamName);
|
||||||
|
if (entryParamIndex < 0) {
|
||||||
|
String tracedVar = traceLocalVariable(entryMethod, currentParamName);
|
||||||
|
if (tracedVar != null && !tracedVar.equals(currentParamName)) {
|
||||||
|
int dotIdx = tracedVar.indexOf('.');
|
||||||
|
if (dotIdx > 0 && dotIdx + 1 < tracedVar.length() && Character.isLowerCase(tracedVar.charAt(dotIdx + 1))) {
|
||||||
|
methodSuffix = tracedVar.substring(dotIdx) + methodSuffix;
|
||||||
|
tracedVar = tracedVar.substring(0, dotIdx);
|
||||||
|
}
|
||||||
|
currentParamName = tracedVar;
|
||||||
|
resolvedValue = tracedVar + methodSuffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> polymorphicEvents = new ArrayList<>();
|
||||||
|
|
||||||
|
// Parse resolvedValue using JDT to robustly handle complex expressions
|
||||||
|
org.eclipse.jdt.core.dom.ASTParser exprParser = org.eclipse.jdt.core.dom.ASTParser.newParser(org.eclipse.jdt.core.dom.AST.getJLSLatest());
|
||||||
|
exprParser.setSource(resolvedValue.toCharArray());
|
||||||
|
exprParser.setKind(org.eclipse.jdt.core.dom.ASTParser.K_EXPRESSION);
|
||||||
|
org.eclipse.jdt.core.dom.ASTNode exprNode = exprParser.createAST(null);
|
||||||
|
|
||||||
|
String varName = null;
|
||||||
|
String methodName = null;
|
||||||
|
String declaredType = null;
|
||||||
|
String sourceMethod = null;
|
||||||
|
|
||||||
|
if (exprNode instanceof org.eclipse.jdt.core.dom.MethodInvocation mi) {
|
||||||
|
methodName = mi.getName().getIdentifier();
|
||||||
|
if (mi.getExpression() instanceof org.eclipse.jdt.core.dom.SimpleName sn) {
|
||||||
|
varName = sn.getIdentifier();
|
||||||
|
} else if (mi.getExpression() instanceof org.eclipse.jdt.core.dom.ParenthesizedExpression pe &&
|
||||||
|
pe.getExpression() instanceof org.eclipse.jdt.core.dom.CastExpression ce &&
|
||||||
|
ce.getExpression() instanceof org.eclipse.jdt.core.dom.SimpleName sn) {
|
||||||
|
varName = sn.getIdentifier();
|
||||||
|
declaredType = ce.getType().toString();
|
||||||
|
sourceMethod = "inline-cast";
|
||||||
|
} else if (mi.getExpression() instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cic) {
|
||||||
|
declaredType = click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cic.getType());
|
||||||
|
sourceMethod = "inline-instantiation";
|
||||||
|
} else {
|
||||||
|
// Fallback for complex chained expressions
|
||||||
|
String exprStr = mi.getExpression() != null ? mi.getExpression().toString() : "";
|
||||||
|
if (!exprStr.contains("(")) {
|
||||||
|
varName = exprStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (exprNode instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cic) {
|
||||||
|
declaredType = click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cic.getType());
|
||||||
|
sourceMethod = "inline-instantiation";
|
||||||
|
polymorphicEvents.add(declaredType); // Track the payload type as the event
|
||||||
|
} else if (exprNode instanceof org.eclipse.jdt.core.dom.ConditionalExpression cond) {
|
||||||
|
if (cond.getThenExpression() instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cicThen) {
|
||||||
|
polymorphicEvents.add(click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cicThen.getType()));
|
||||||
|
}
|
||||||
|
if (cond.getElseExpression() instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cicElse) {
|
||||||
|
polymorphicEvents.add(click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cicElse.getType()));
|
||||||
|
}
|
||||||
|
sourceMethod = "inline-ternary";
|
||||||
|
declaredType = polymorphicEvents.isEmpty() ? null : polymorphicEvents.get(0);
|
||||||
|
} else if (exprNode instanceof org.eclipse.jdt.core.dom.SimpleName sn) {
|
||||||
|
varName = sn.getIdentifier();
|
||||||
|
methodName = "VariableReference"; // We just want to trigger deep trace
|
||||||
|
} else if (exprNode instanceof org.eclipse.jdt.core.dom.ParenthesizedExpression pe &&
|
||||||
|
pe.getExpression() instanceof org.eclipse.jdt.core.dom.CastExpression ce &&
|
||||||
|
ce.getExpression() instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cic) {
|
||||||
|
declaredType = click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cic.getType());
|
||||||
|
sourceMethod = "inline-instantiation";
|
||||||
|
polymorphicEvents.add(declaredType);
|
||||||
|
} else if (exprNode instanceof org.eclipse.jdt.core.dom.CastExpression ce &&
|
||||||
|
ce.getExpression() instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cic) {
|
||||||
|
declaredType = click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cic.getType());
|
||||||
|
sourceMethod = "inline-instantiation";
|
||||||
|
polymorphicEvents.add(declaredType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodName != null) {
|
||||||
|
if (varName != null && declaredType == null) {
|
||||||
|
for (String methodFqn : path) {
|
||||||
|
declaredType = getVariableDeclaredType(methodFqn, varName);
|
||||||
|
if (declaredType != null) {
|
||||||
|
sourceMethod = methodFqn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If it wasn't a variable, it might be a static method call (e.g., EventBuilder.buildEvent())
|
||||||
|
if (declaredType == null && varName.matches("^[A-Z].*")) {
|
||||||
|
org.eclipse.jdt.core.dom.TypeDeclaration staticTd = context.getTypeDeclaration(varName);
|
||||||
|
if (staticTd != null) {
|
||||||
|
declaredType = context.getFqn(staticTd);
|
||||||
|
sourceMethod = "static-call";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (declaredType != null) {
|
||||||
|
System.out.println("DEEP TRACE: " + sourceMethod + " " + (varName != null ? varName : "inline") + " -> " + declaredType);
|
||||||
|
List<String> typesToInspect = new ArrayList<>();
|
||||||
|
if ("inline-instantiation".equals(sourceMethod)) {
|
||||||
|
typesToInspect.add(declaredType);
|
||||||
|
} else {
|
||||||
|
typesToInspect.add(declaredType);
|
||||||
|
typesToInspect.addAll(context.getImplementations(declaredType));
|
||||||
|
}
|
||||||
|
System.out.println("DEEP TRACE IMPLS: " + typesToInspect);
|
||||||
|
|
||||||
|
for (String type : typesToInspect) {
|
||||||
|
Set<String> visited = new HashSet<>();
|
||||||
|
TypeDeclaration baseTd = context.getTypeDeclaration(type);
|
||||||
|
CompilationUnit cuToUse = null;
|
||||||
|
if (baseTd != null && baseTd.getRoot() instanceof CompilationUnit) {
|
||||||
|
cuToUse = (CompilationUnit) baseTd.getRoot();
|
||||||
|
} else {
|
||||||
|
String firstPathMethod = path.get(0);
|
||||||
|
String entryClassName = firstPathMethod.substring(0, firstPathMethod.lastIndexOf('.'));
|
||||||
|
TypeDeclaration entryTd = context.getTypeDeclaration(entryClassName);
|
||||||
|
if (entryTd != null && entryTd.getRoot() instanceof CompilationUnit) {
|
||||||
|
cuToUse = (CompilationUnit) entryTd.getRoot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> constants = resolveMethodReturnConstant(type, methodName, 0, visited, cuToUse);
|
||||||
|
System.out.println("DEEP TRACE RETURN: " + type + " -> " + constants);
|
||||||
|
for (String constant : constants) {
|
||||||
|
if (!polymorphicEvents.contains(constant)) {
|
||||||
|
polymorphicEvents.add(constant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// (e.g. it returned a field name like 'type', or nothing), we can scrape the resolvedValue string directly
|
||||||
|
// for string literals or enum-like constants.
|
||||||
|
boolean hasValidConstant = false;
|
||||||
|
for (String ev : polymorphicEvents) {
|
||||||
|
String val = ev.contains(".") ? ev.substring(ev.lastIndexOf('.') + 1) : ev;
|
||||||
|
if (val.equals(val.toUpperCase()) && val.length() > 2) {
|
||||||
|
hasValidConstant = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasValidConstant && resolvedValue.contains("(")) {
|
||||||
|
java.util.List<String> scraped = new java.util.ArrayList<>();
|
||||||
|
|
||||||
|
// Extract "STRING_LITERALS"
|
||||||
|
java.util.regex.Matcher m1 = java.util.regex.Pattern.compile("\"([^\"]+)\"").matcher(resolvedValue);
|
||||||
|
while (m1.find()) {
|
||||||
|
scraped.add(m1.group(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract ENUM_LIKE_CONSTANTS
|
||||||
|
java.util.regex.Matcher m2 = java.util.regex.Pattern.compile("\\b([A-Z_]{3,})\\b").matcher(resolvedValue);
|
||||||
|
while (m2.find()) {
|
||||||
|
if (!scraped.contains(m2.group(1))) {
|
||||||
|
scraped.add(m2.group(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scraped.isEmpty()) {
|
||||||
|
polymorphicEvents.clear();
|
||||||
|
polymorphicEvents.addAll(scraped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up any remaining invalid AST fallbacks (like 'type', 'event') if we found valid ones
|
||||||
|
if (polymorphicEvents.size() > 1) {
|
||||||
|
polymorphicEvents.removeIf(e -> {
|
||||||
|
String val = e.contains(".") ? e.substring(e.lastIndexOf('.') + 1) : e;
|
||||||
|
return !val.equals(val.toUpperCase()) || val.length() <= 2;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
List<String> newPolyEvents = new ArrayList<>();
|
||||||
|
for (String pe : polymorphicEvents) {
|
||||||
|
List<String> resolved = resolveClassConstantReturns(pe, context, null);
|
||||||
|
if (resolved != null && !resolved.isEmpty()) {
|
||||||
|
newPolyEvents.addAll(resolved);
|
||||||
|
} else {
|
||||||
|
newPolyEvents.add(pe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
polymorphicEvents = newPolyEvents;
|
||||||
|
|
||||||
|
if (!resolvedValue.equals(event) || !polymorphicEvents.isEmpty()) {
|
||||||
|
return TriggerPoint.builder()
|
||||||
|
.event(resolvedValue)
|
||||||
|
.className(tp.getClassName())
|
||||||
|
.methodName(tp.getMethodName())
|
||||||
|
.sourceFile(tp.getSourceFile())
|
||||||
|
.lineNumber(tp.getLineNumber())
|
||||||
|
.polymorphicEvents(polymorphicEvents)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getParameterIndex(String methodFqn, String paramName) {
|
||||||
|
if (methodFqn == null || !methodFqn.contains(".")) return -1;
|
||||||
|
String className = methodFqn.substring(0, methodFqn.lastIndexOf('.'));
|
||||||
|
String methodName = methodFqn.substring(methodFqn.lastIndexOf('.') + 1);
|
||||||
|
TypeDeclaration td = context.getTypeDeclaration(className);
|
||||||
|
if (td != null) {
|
||||||
|
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
||||||
|
if (md != null) {
|
||||||
|
for (int i = 0; i < md.parameters().size(); i++) {
|
||||||
|
SingleVariableDeclaration svd = (SingleVariableDeclaration) md.parameters().get(i);
|
||||||
|
if (svd.getName().getIdentifier().equals(paramName)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getVariableDeclaredType(String methodFqn, String varName) {
|
||||||
|
if (methodFqn == null || !methodFqn.contains(".")) return null;
|
||||||
|
String className = methodFqn.substring(0, methodFqn.lastIndexOf('.'));
|
||||||
|
String methodName = methodFqn.substring(methodFqn.lastIndexOf('.') + 1);
|
||||||
|
TypeDeclaration td = context.getTypeDeclaration(className);
|
||||||
|
if (td != null) {
|
||||||
|
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
||||||
|
if (md != null) {
|
||||||
|
for (Object pObj : md.parameters()) {
|
||||||
|
SingleVariableDeclaration svd = (SingleVariableDeclaration) pObj;
|
||||||
|
if (svd.getName().getIdentifier().equals(varName)) {
|
||||||
|
return svd.getType().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String[] foundType = new String[1];
|
||||||
|
if (md.getBody() != null) {
|
||||||
|
md.getBody().accept(new ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(VariableDeclarationStatement node) {
|
||||||
|
for (Object fragObj : node.fragments()) {
|
||||||
|
VariableDeclarationFragment frag = (VariableDeclarationFragment) fragObj;
|
||||||
|
if (frag.getName().getIdentifier().equals(varName)) {
|
||||||
|
foundType[0] = node.getType().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return foundType[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> resolveMethodReturnConstant(String className, String methodName, int depth, Set<String> visited, CompilationUnit contextCu) {
|
||||||
|
if (depth > 20) return Collections.emptyList();
|
||||||
|
String fqn = className + "." + methodName;
|
||||||
|
if (!visited.add(fqn)) return Collections.emptyList();
|
||||||
|
|
||||||
|
List<String> constants = new ArrayList<>();
|
||||||
|
TypeDeclaration tempTd = contextCu != null ? context.getTypeDeclaration(className, contextCu) : null;
|
||||||
|
if (tempTd == null) {
|
||||||
|
tempTd = context.getTypeDeclaration(className);
|
||||||
|
}
|
||||||
|
final TypeDeclaration td = tempTd;
|
||||||
|
if (td == null) {
|
||||||
|
System.out.println("DEEP TRACE FAILED TO FIND TD: " + className);
|
||||||
|
}
|
||||||
|
if (td != null) {
|
||||||
|
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
||||||
|
if (md != null && md.getBody() != null) {
|
||||||
|
md.getBody().accept(new ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(ReturnStatement node) {
|
||||||
|
Expression retExpr = node.getExpression();
|
||||||
|
if (retExpr != null) {
|
||||||
|
boolean handled = false;
|
||||||
|
if (retExpr instanceof MethodInvocation mi) {
|
||||||
|
// Follow delegation first
|
||||||
|
String called = resolveCalledMethod(mi);
|
||||||
|
System.out.println("DEEP TRACE RESOLVED CALLED: " + called);
|
||||||
|
if (called != null && called.contains(".")) {
|
||||||
|
if (visited.contains(called)) {
|
||||||
|
handled = true;
|
||||||
|
} else {
|
||||||
|
String cName = called.substring(0, called.lastIndexOf('.'));
|
||||||
|
String mName = called.substring(called.lastIndexOf('.') + 1);
|
||||||
|
|
||||||
|
TypeDeclaration targetTd = contextCu != null ? context.getTypeDeclaration(cName, contextCu) : context.getTypeDeclaration(cName);
|
||||||
|
if (targetTd == null) targetTd = context.getTypeDeclaration(cName);
|
||||||
|
|
||||||
|
if (targetTd != null && context.findMethodDeclaration(targetTd, mName, true) != null) {
|
||||||
|
List<String> delegationResult = resolveMethodReturnConstant(cName, mName, depth + 1, visited, contextCu);
|
||||||
|
constants.addAll(delegationResult);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!handled) {
|
||||||
|
String val = constantResolver.resolve(retExpr, context);
|
||||||
|
if (val != null) {
|
||||||
|
if (val.startsWith("ENUM_SET:")) {
|
||||||
|
for (String eVal : val.substring(9).split(",")) {
|
||||||
|
constants.add(eVal.substring(eVal.lastIndexOf('.') + 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
constants.add(val);
|
||||||
|
}
|
||||||
|
} else if (retExpr instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cic) {
|
||||||
|
constants.add(click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cic.getType()));
|
||||||
|
} else if (retExpr instanceof QualifiedName qn) {
|
||||||
|
constants.add(qn.toString());
|
||||||
|
} else if (retExpr instanceof SimpleName sn) {
|
||||||
|
List<String> consts = traceFieldInConstructors(td, sn.getIdentifier(), context, visited);
|
||||||
|
if (!consts.isEmpty()) {
|
||||||
|
constants.addAll(consts);
|
||||||
|
} else {
|
||||||
|
constants.add(sn.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visited.remove(fqn);
|
||||||
|
return constants;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> resolveClassConstantReturns(String className, click.kamil.springstatemachineexporter.ast.common.CodebaseContext context, CompilationUnit contextCu) {
|
||||||
|
TypeDeclaration td = contextCu != null ? context.getTypeDeclaration(className, contextCu) : context.getTypeDeclaration(className);
|
||||||
|
if (td == null) td = context.getTypeDeclaration(className);
|
||||||
|
if (td == null) return null;
|
||||||
|
|
||||||
|
final List<String> resolvedConstants = new ArrayList<>();
|
||||||
|
for (MethodDeclaration md : td.getMethods()) {
|
||||||
|
if (md.getBody() != null) {
|
||||||
|
md.getBody().accept(new ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(ReturnStatement node) {
|
||||||
|
if (node.getExpression() instanceof QualifiedName qn) {
|
||||||
|
resolvedConstants.add(qn.getName().getIdentifier());
|
||||||
|
} else if (node.getExpression() instanceof org.eclipse.jdt.core.dom.StringLiteral sl) {
|
||||||
|
resolvedConstants.add(sl.getLiteralValue());
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!resolvedConstants.isEmpty()) return resolvedConstants;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String traceLocalVariable(String methodFqn, String varName) {
|
||||||
|
if (methodFqn == null || !methodFqn.contains(".")) return null;
|
||||||
|
String className = methodFqn.substring(0, methodFqn.lastIndexOf('.'));
|
||||||
|
String methodName = methodFqn.substring(methodFqn.lastIndexOf('.') + 1);
|
||||||
|
TypeDeclaration td = context.getTypeDeclaration(className);
|
||||||
|
if (td != null) {
|
||||||
|
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
||||||
|
if (md != null && md.getBody() != null) {
|
||||||
|
final Expression[] initializer = new Expression[1];
|
||||||
|
md.getBody().accept(new ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(VariableDeclarationFragment node) {
|
||||||
|
if (node.getName().getIdentifier().equals(varName) && node.getInitializer() != null) {
|
||||||
|
initializer[0] = node.getInitializer();
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean visit(Assignment node) {
|
||||||
|
if (node.getLeftHandSide() instanceof SimpleName asn && asn.getIdentifier().equals(varName)) {
|
||||||
|
initializer[0] = node.getRightHandSide();
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (initializer[0] != null) {
|
||||||
|
Expression expr = traceVariable(initializer[0]);
|
||||||
|
if (expr instanceof MethodInvocation mi) {
|
||||||
|
// Unwrapper logic: If wrapper method is called, extract its arguments recursively
|
||||||
|
Expression innerMost = unwrapMethodInvocation(mi, 0);
|
||||||
|
if (innerMost instanceof MethodInvocation innerMi) {
|
||||||
|
if (innerMi.getExpression() instanceof SimpleName sn) {
|
||||||
|
return sn.getIdentifier() + "." + innerMi.getName().getIdentifier() + "()";
|
||||||
|
}
|
||||||
|
return innerMi.getName().getIdentifier() + "()";
|
||||||
|
}
|
||||||
|
if (innerMost instanceof SimpleName sn) {
|
||||||
|
return sn.getIdentifier();
|
||||||
|
}
|
||||||
|
return innerMost.toString();
|
||||||
|
}
|
||||||
|
if (expr instanceof SimpleName sn) {
|
||||||
|
return sn.getIdentifier();
|
||||||
|
}
|
||||||
|
return expr.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Expression unwrapMethodInvocation(MethodInvocation mi, int depth) {
|
||||||
|
if (depth > 5) return mi;
|
||||||
|
if (!mi.arguments().isEmpty()) {
|
||||||
|
Expression arg = (Expression) mi.arguments().get(0);
|
||||||
|
if (arg instanceof MethodInvocation innerMi) {
|
||||||
|
return unwrapMethodInvocation(innerMi, depth + 1);
|
||||||
|
}
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
return mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractContextMachineId(List<String> path, Map<String, List<CallEdge>> callGraph) {
|
||||||
|
for (String node : path) {
|
||||||
|
List<CallEdge> edges = callGraph.get(node);
|
||||||
|
if (edges != null) {
|
||||||
|
for (CallEdge edge : edges) {
|
||||||
|
String target = edge.getTargetMethod();
|
||||||
|
if (target != null && (target.contains(".restore") || target.contains(".read"))) {
|
||||||
|
// Persister signatures usually like: restore(stateMachine, contextObj)
|
||||||
|
if (edge.getArguments().size() >= 2) {
|
||||||
|
return edge.getArguments().get(1); // The contextObj / machineId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodDeclaration findEnclosingMethod(ASTNode node) {
|
||||||
|
ASTNode parent = node.getParent();
|
||||||
|
while (parent != null && !(parent instanceof MethodDeclaration)) {
|
||||||
|
parent = parent.getParent();
|
||||||
|
}
|
||||||
|
return (MethodDeclaration) parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, List<CallEdge>> buildCallGraph() {
|
||||||
graph = new HashMap<>();
|
graph = new HashMap<>();
|
||||||
for (CompilationUnit cu : context.getCompilationUnits()) {
|
for (CompilationUnit cu : context.getCompilationUnits()) {
|
||||||
cu.accept(new ASTVisitor() {
|
cu.accept(new ASTVisitor() {
|
||||||
@@ -106,7 +656,7 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<String> resolveArguments(List<?> astArguments) {
|
private List<String> resolveArguments(List<?> astArguments) {
|
||||||
List<String> args = new ArrayList<>();
|
List<String> args = new ArrayList<>();
|
||||||
for (Object argObj : astArguments) {
|
for (Object argObj : astArguments) {
|
||||||
Expression expr = (Expression) argObj;
|
Expression expr = (Expression) argObj;
|
||||||
@@ -164,7 +714,7 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<String> resolveCalledMethodsPolymorphic(MethodInvocation node) {
|
private List<String> resolveCalledMethodsPolymorphic(MethodInvocation node) {
|
||||||
String baseCalled = resolveCalledMethod(node);
|
String baseCalled = resolveCalledMethod(node);
|
||||||
if (baseCalled == null) return Collections.emptyList();
|
if (baseCalled == null) return Collections.emptyList();
|
||||||
|
|
||||||
@@ -184,7 +734,7 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
return allResolved;
|
return allResolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String resolveCalledMethod(MethodInvocation node) {
|
private String resolveCalledMethod(MethodInvocation node) {
|
||||||
Expression receiver = node.getExpression();
|
Expression receiver = node.getExpression();
|
||||||
String methodName = node.getName().getIdentifier();
|
String methodName = node.getName().getIdentifier();
|
||||||
|
|
||||||
@@ -220,7 +770,7 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String resolveReceiverTypeFallback(SimpleName receiverNameNode) {
|
private String resolveReceiverTypeFallback(SimpleName receiverNameNode) {
|
||||||
String varName = receiverNameNode.getIdentifier();
|
String varName = receiverNameNode.getIdentifier();
|
||||||
|
|
||||||
// 1. Check local variables in enclosing method
|
// 1. Check local variables in enclosing method
|
||||||
@@ -270,7 +820,7 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String resolveTypeToFqn(Type type, ASTNode contextNode) {
|
private String resolveTypeToFqn(Type type, ASTNode contextNode) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
String simpleName;
|
String simpleName;
|
||||||
if (type.isSimpleType()) {
|
if (type.isSimpleType()) {
|
||||||
@@ -299,7 +849,7 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
return simpleName;
|
return simpleName;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String resolveMethodInType(TypeDeclaration td, String methodName) {
|
private String resolveMethodInType(TypeDeclaration td, String methodName) {
|
||||||
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
||||||
if (md != null) {
|
if (md != null) {
|
||||||
TypeDeclaration declaringTd = findEnclosingType(md);
|
TypeDeclaration declaringTd = findEnclosingType(md);
|
||||||
@@ -308,4 +858,185 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> findPath(String start, String target, Map<String, List<CallEdge>> graph, Set<String> visited) {
|
||||||
|
if (start.equals(target)) return new ArrayList<>(List.of(start));
|
||||||
|
if (!visited.add(start)) return null; // Path-scoped cycle detection
|
||||||
|
|
||||||
|
List<CallEdge> neighbors = graph.get(start);
|
||||||
|
if (neighbors != null) {
|
||||||
|
for (CallEdge edge : neighbors) {
|
||||||
|
String neighbor = edge.getTargetMethod();
|
||||||
|
if (neighbor.equals(target) || isHeuristicMatch(neighbor, target)) {
|
||||||
|
visited.remove(start);
|
||||||
|
return new ArrayList<>(List.of(start, target));
|
||||||
|
}
|
||||||
|
List<String> path = findPath(neighbor, target, graph, visited);
|
||||||
|
if (path != null) {
|
||||||
|
path.add(0, start);
|
||||||
|
visited.remove(start);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Path search dead-end at {} when looking for {}", start, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
visited.remove(start);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHeuristicMatch(String neighbor, String target) {
|
||||||
|
if (target.endsWith("." + neighbor)) return true;
|
||||||
|
String simpleTarget = target.contains(".") ? target.substring(target.lastIndexOf('.') + 1) : target;
|
||||||
|
String simpleNeighbor = neighbor.contains(".") ? neighbor.substring(neighbor.lastIndexOf('.') + 1) : neighbor;
|
||||||
|
return simpleNeighbor.equals(simpleTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeDeclaration findEnclosingType(ASTNode node) {
|
||||||
|
ASTNode parent = node.getParent();
|
||||||
|
while (parent != null && !(parent instanceof TypeDeclaration)) {
|
||||||
|
parent = parent.getParent();
|
||||||
|
}
|
||||||
|
return (TypeDeclaration) parent;
|
||||||
|
}
|
||||||
|
private Expression traceVariable(Expression expr) {
|
||||||
|
if (expr instanceof SimpleName sn) {
|
||||||
|
String varName = sn.getIdentifier();
|
||||||
|
MethodDeclaration enclosingMethod = findEnclosingMethod(expr);
|
||||||
|
if (enclosingMethod != null) {
|
||||||
|
final Expression[] initializer = new Expression[1];
|
||||||
|
enclosingMethod.accept(new ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(VariableDeclarationFragment node) {
|
||||||
|
if (node.getName().getIdentifier().equals(varName) && node.getInitializer() != null) {
|
||||||
|
initializer[0] = node.getInitializer();
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean visit(Assignment node) {
|
||||||
|
if (node.getLeftHandSide() instanceof SimpleName asn && asn.getIdentifier().equals(varName)) {
|
||||||
|
initializer[0] = node.getRightHandSide();
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (initializer[0] != null) {
|
||||||
|
return traceVariable(initializer[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> traceFieldInConstructors(TypeDeclaration td, String fieldName, CodebaseContext context, Set<String> visited) {
|
||||||
|
List<String> results = new ArrayList<>();
|
||||||
|
|
||||||
|
// 1. Check Field Declarations
|
||||||
|
for (org.eclipse.jdt.core.dom.FieldDeclaration fd : td.getFields()) {
|
||||||
|
for (Object fragObj : fd.fragments()) {
|
||||||
|
org.eclipse.jdt.core.dom.VariableDeclarationFragment frag = (org.eclipse.jdt.core.dom.VariableDeclarationFragment) fragObj;
|
||||||
|
if (frag.getName().getIdentifier().equals(fieldName) && frag.getInitializer() != null) {
|
||||||
|
Expression right = frag.getInitializer();
|
||||||
|
if (right instanceof MethodInvocation mi) {
|
||||||
|
String calledName = mi.getName().getIdentifier();
|
||||||
|
String targetClass = context.getFqn(td);
|
||||||
|
CompilationUnit cu = td.getRoot() instanceof CompilationUnit ? (CompilationUnit) td.getRoot() : null;
|
||||||
|
results.addAll(resolveMethodReturnConstant(targetClass, calledName, 0, new HashSet<>(visited), cu));
|
||||||
|
} else {
|
||||||
|
String val = constantResolver.resolve(right, context);
|
||||||
|
if (val != null) results.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
org.eclipse.jdt.core.dom.ASTVisitor assignmentVisitor = new org.eclipse.jdt.core.dom.ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(Assignment node) {
|
||||||
|
Expression left = node.getLeftHandSide();
|
||||||
|
if ((left instanceof SimpleName && ((SimpleName) left).getIdentifier().equals(fieldName)) ||
|
||||||
|
(left instanceof FieldAccess && ((FieldAccess) left).getName().getIdentifier().equals(fieldName))) {
|
||||||
|
|
||||||
|
Expression right = node.getRightHandSide();
|
||||||
|
if (right instanceof MethodInvocation mi) {
|
||||||
|
String calledName = mi.getName().getIdentifier();
|
||||||
|
String targetClass = context.getFqn(td);
|
||||||
|
|
||||||
|
if (mi.getExpression() != null && mi.resolveMethodBinding() != null && mi.resolveMethodBinding().getDeclaringClass() != null) {
|
||||||
|
targetClass = mi.resolveMethodBinding().getDeclaringClass().getQualifiedName();
|
||||||
|
} else if (mi.getExpression() instanceof SimpleName) {
|
||||||
|
String exprName = ((SimpleName) mi.getExpression()).getIdentifier();
|
||||||
|
CompilationUnit cu = td.getRoot() instanceof CompilationUnit ? (CompilationUnit) td.getRoot() : null;
|
||||||
|
TypeDeclaration targetTd = context.resolveStaticImport(exprName, cu);
|
||||||
|
if (targetTd != null) {
|
||||||
|
targetClass = context.getFqn(targetTd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilationUnit cu = td.getRoot() instanceof CompilationUnit ? (CompilationUnit) td.getRoot() : null;
|
||||||
|
results.addAll(resolveMethodReturnConstant(targetClass, calledName, 0, new HashSet<>(visited), cu));
|
||||||
|
} else {
|
||||||
|
String val = constantResolver.resolve(right, context);
|
||||||
|
if (val != null) results.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean visit(ConstructorInvocation node) {
|
||||||
|
for (Object argObj : node.arguments()) {
|
||||||
|
Expression arg = (Expression) argObj;
|
||||||
|
String val = constantResolver.resolve(arg, context);
|
||||||
|
if (val != null) {
|
||||||
|
if (val.startsWith("ENUM_SET:")) {
|
||||||
|
for (String eVal : val.substring(9).split(",")) {
|
||||||
|
results.add(eVal.substring(eVal.lastIndexOf('.') + 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
results.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(SuperConstructorInvocation node) {
|
||||||
|
for (Object argObj : node.arguments()) {
|
||||||
|
Expression arg = (Expression) argObj;
|
||||||
|
String val = constantResolver.resolve(arg, context);
|
||||||
|
if (val != null) {
|
||||||
|
if (val.startsWith("ENUM_SET:")) {
|
||||||
|
for (String eVal : val.substring(9).split(",")) {
|
||||||
|
results.add(eVal.substring(eVal.lastIndexOf('.') + 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
results.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Check Constructors
|
||||||
|
for (MethodDeclaration md : td.getMethods()) {
|
||||||
|
if (md.isConstructor() && md.getBody() != null) {
|
||||||
|
md.getBody().accept(assignmentVisitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Check Initializers
|
||||||
|
for (Object bodyDecl : td.bodyDeclarations()) {
|
||||||
|
if (bodyDecl instanceof org.eclipse.jdt.core.dom.Initializer init && init.getBody() != null) {
|
||||||
|
init.getBody().accept(assignmentVisitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,567 @@ import java.util.*;
|
|||||||
import click.kamil.springstatemachineexporter.analysis.spring.InjectionPointAnalyzer;
|
import click.kamil.springstatemachineexporter.analysis.spring.InjectionPointAnalyzer;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class JdtCallGraphEngine extends AbstractCallGraphEngine {
|
public class JdtCallGraphEngine implements CallGraphEngine {
|
||||||
|
private final CodebaseContext context;
|
||||||
|
private final ConstantResolver constantResolver;
|
||||||
private final InjectionPointAnalyzer injectionAnalyzer;
|
private final InjectionPointAnalyzer injectionAnalyzer;
|
||||||
private String currentMethodFqn;
|
private String currentMethodFqn;
|
||||||
private Map<String, List<CallEdge>> graph;
|
private Map<String, List<CallEdge>> graph;
|
||||||
|
|
||||||
public JdtCallGraphEngine(CodebaseContext context, InjectionPointAnalyzer injectionAnalyzer) {
|
public JdtCallGraphEngine(CodebaseContext context, InjectionPointAnalyzer injectionAnalyzer) {
|
||||||
super(context);
|
this.context = context;
|
||||||
|
this.constantResolver = new ConstantResolver();
|
||||||
this.injectionAnalyzer = injectionAnalyzer;
|
this.injectionAnalyzer = injectionAnalyzer;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, List<CallEdge>> buildCallGraph() {
|
public List<CallChain> findChains(List<EntryPoint> entryPoints, List<TriggerPoint> triggers) {
|
||||||
|
Map<String, List<CallEdge>> callGraph = buildCallGraph();
|
||||||
|
List<CallChain> chains = new ArrayList<>();
|
||||||
|
|
||||||
|
for (EntryPoint ep : entryPoints) {
|
||||||
|
String startMethod = ep.getClassName() + "." + ep.getMethodName();
|
||||||
|
boolean foundAny = false;
|
||||||
|
for (TriggerPoint tp : triggers) {
|
||||||
|
String targetMethod = tp.getClassName() + "." + tp.getMethodName();
|
||||||
|
List<String> path = findPath(startMethod, targetMethod, callGraph, new HashSet<>());
|
||||||
|
if (path != null) {
|
||||||
|
foundAny = true;
|
||||||
|
TriggerPoint resolvedTp = resolveTriggerPointParameters(tp, path, callGraph);
|
||||||
|
String contextMachineId = extractContextMachineId(path, callGraph);
|
||||||
|
chains.add(CallChain.builder()
|
||||||
|
.entryPoint(ep)
|
||||||
|
.triggerPoint(resolvedTp)
|
||||||
|
.methodChain(path)
|
||||||
|
.contextMachineId(contextMachineId)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundAny && log.isDebugEnabled()) {
|
||||||
|
log.debug("Entry point {} ({}) did not reach any trigger points. Graph nodes available: {}", ep.getName(), startMethod, callGraph.keySet());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chains;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TriggerPoint resolveTriggerPointParameters(TriggerPoint tp, List<String> path, Map<String, List<CallEdge>> callGraph) {
|
||||||
|
if (path.size() < 2) return tp;
|
||||||
|
|
||||||
|
String event = tp.getEvent();
|
||||||
|
if (event == null || event.isEmpty() || event.contains("\"")) return tp;
|
||||||
|
|
||||||
|
String currentParamName = event;
|
||||||
|
String resolvedValue = event;
|
||||||
|
String methodSuffix = "";
|
||||||
|
|
||||||
|
// Extract method calls like .getType() so we can trace the base parameter
|
||||||
|
int dotIndex = currentParamName.indexOf('.');
|
||||||
|
if (dotIndex > 0 && dotIndex + 1 < currentParamName.length()) {
|
||||||
|
char nextChar = currentParamName.charAt(dotIndex + 1);
|
||||||
|
if (Character.isLowerCase(nextChar)) {
|
||||||
|
methodSuffix = currentParamName.substring(dotIndex);
|
||||||
|
currentParamName = currentParamName.substring(0, dotIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk backwards up the call chain
|
||||||
|
for (int i = path.size() - 1; i > 0; i--) {
|
||||||
|
String target = path.get(i);
|
||||||
|
String caller = path.get(i - 1);
|
||||||
|
|
||||||
|
// Find parameter index in target method
|
||||||
|
int paramIndex = getParameterIndex(target, currentParamName);
|
||||||
|
if (paramIndex < 0) {
|
||||||
|
// Not a parameter. Maybe it's a local variable initialized from a parameter or method call?
|
||||||
|
String tracedVar = traceLocalVariable(target, currentParamName);
|
||||||
|
if (tracedVar != null && !tracedVar.equals(currentParamName)) {
|
||||||
|
// Extract method calls like .getType() from the traced variable
|
||||||
|
int dotIdx = tracedVar.indexOf('.');
|
||||||
|
if (dotIdx > 0 && dotIdx + 1 < tracedVar.length() && Character.isLowerCase(tracedVar.charAt(dotIdx + 1))) {
|
||||||
|
methodSuffix = tracedVar.substring(dotIdx) + methodSuffix;
|
||||||
|
tracedVar = tracedVar.substring(0, dotIdx);
|
||||||
|
}
|
||||||
|
currentParamName = tracedVar;
|
||||||
|
resolvedValue = tracedVar + methodSuffix;
|
||||||
|
paramIndex = getParameterIndex(target, currentParamName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (paramIndex < 0) {
|
||||||
|
break; // Parameter name changed or not found, stop tracing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the edge from caller to target to get the argument passed
|
||||||
|
List<CallEdge> edges = callGraph.get(caller);
|
||||||
|
boolean found = false;
|
||||||
|
if (edges != null) {
|
||||||
|
for (CallEdge edge : edges) {
|
||||||
|
if (edge.getTargetMethod().equals(target) || isHeuristicMatch(edge.getTargetMethod(), target)) {
|
||||||
|
if (paramIndex < edge.getArguments().size()) {
|
||||||
|
String arg = edge.getArguments().get(paramIndex);
|
||||||
|
if (arg != null) {
|
||||||
|
// If the argument passed has a method call, extract it
|
||||||
|
int dotIdx = arg.indexOf('.');
|
||||||
|
if (dotIdx > 0 && dotIdx + 1 < arg.length() && Character.isLowerCase(arg.charAt(dotIdx + 1))) {
|
||||||
|
methodSuffix = arg.substring(dotIdx) + methodSuffix;
|
||||||
|
arg = arg.substring(0, dotIdx);
|
||||||
|
}
|
||||||
|
currentParamName = arg;
|
||||||
|
resolvedValue = arg + methodSuffix;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) break; // Could not map argument
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final check on the entry method
|
||||||
|
String entryMethod = path.get(0);
|
||||||
|
int entryParamIndex = getParameterIndex(entryMethod, currentParamName);
|
||||||
|
if (entryParamIndex < 0) {
|
||||||
|
String tracedVar = traceLocalVariable(entryMethod, currentParamName);
|
||||||
|
if (tracedVar != null && !tracedVar.equals(currentParamName)) {
|
||||||
|
int dotIdx = tracedVar.indexOf('.');
|
||||||
|
if (dotIdx > 0 && dotIdx + 1 < tracedVar.length() && Character.isLowerCase(tracedVar.charAt(dotIdx + 1))) {
|
||||||
|
methodSuffix = tracedVar.substring(dotIdx) + methodSuffix;
|
||||||
|
tracedVar = tracedVar.substring(0, dotIdx);
|
||||||
|
}
|
||||||
|
currentParamName = tracedVar;
|
||||||
|
resolvedValue = tracedVar + methodSuffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> polymorphicEvents = new ArrayList<>();
|
||||||
|
|
||||||
|
// Parse resolvedValue using JDT to robustly handle complex expressions
|
||||||
|
org.eclipse.jdt.core.dom.ASTParser exprParser = org.eclipse.jdt.core.dom.ASTParser.newParser(org.eclipse.jdt.core.dom.AST.getJLSLatest());
|
||||||
|
exprParser.setSource(resolvedValue.toCharArray());
|
||||||
|
exprParser.setKind(org.eclipse.jdt.core.dom.ASTParser.K_EXPRESSION);
|
||||||
|
org.eclipse.jdt.core.dom.ASTNode exprNode = exprParser.createAST(null);
|
||||||
|
|
||||||
|
String varName = null;
|
||||||
|
String methodName = null;
|
||||||
|
String declaredType = null;
|
||||||
|
String sourceMethod = null;
|
||||||
|
|
||||||
|
if (exprNode instanceof org.eclipse.jdt.core.dom.MethodInvocation mi) {
|
||||||
|
methodName = mi.getName().getIdentifier();
|
||||||
|
if (mi.getExpression() instanceof org.eclipse.jdt.core.dom.SimpleName sn) {
|
||||||
|
varName = sn.getIdentifier();
|
||||||
|
} else if (mi.getExpression() instanceof org.eclipse.jdt.core.dom.ParenthesizedExpression pe &&
|
||||||
|
pe.getExpression() instanceof org.eclipse.jdt.core.dom.CastExpression ce &&
|
||||||
|
ce.getExpression() instanceof org.eclipse.jdt.core.dom.SimpleName sn) {
|
||||||
|
varName = sn.getIdentifier();
|
||||||
|
declaredType = ce.getType().toString();
|
||||||
|
sourceMethod = "inline-cast";
|
||||||
|
} else if (mi.getExpression() instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cic) {
|
||||||
|
declaredType = click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cic.getType());
|
||||||
|
sourceMethod = "inline-instantiation";
|
||||||
|
} else {
|
||||||
|
// Fallback for complex chained expressions
|
||||||
|
String exprStr = mi.getExpression() != null ? mi.getExpression().toString() : "";
|
||||||
|
if (!exprStr.contains("(")) {
|
||||||
|
varName = exprStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (exprNode instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cic) {
|
||||||
|
declaredType = click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cic.getType());
|
||||||
|
sourceMethod = "inline-instantiation";
|
||||||
|
polymorphicEvents.add(declaredType); // Track the payload type as the event
|
||||||
|
} else if (exprNode instanceof org.eclipse.jdt.core.dom.ConditionalExpression cond) {
|
||||||
|
if (cond.getThenExpression() instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cicThen) {
|
||||||
|
polymorphicEvents.add(click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cicThen.getType()));
|
||||||
|
}
|
||||||
|
if (cond.getElseExpression() instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cicElse) {
|
||||||
|
polymorphicEvents.add(click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cicElse.getType()));
|
||||||
|
}
|
||||||
|
sourceMethod = "inline-ternary";
|
||||||
|
declaredType = polymorphicEvents.isEmpty() ? null : polymorphicEvents.get(0);
|
||||||
|
} else if (exprNode instanceof org.eclipse.jdt.core.dom.SimpleName sn) {
|
||||||
|
varName = sn.getIdentifier();
|
||||||
|
methodName = "VariableReference"; // We just want to trigger deep trace
|
||||||
|
} else if (exprNode instanceof org.eclipse.jdt.core.dom.ParenthesizedExpression pe &&
|
||||||
|
pe.getExpression() instanceof org.eclipse.jdt.core.dom.CastExpression ce &&
|
||||||
|
ce.getExpression() instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cic) {
|
||||||
|
declaredType = click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cic.getType());
|
||||||
|
sourceMethod = "inline-instantiation";
|
||||||
|
polymorphicEvents.add(declaredType);
|
||||||
|
} else if (exprNode instanceof org.eclipse.jdt.core.dom.CastExpression ce &&
|
||||||
|
ce.getExpression() instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cic) {
|
||||||
|
declaredType = click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cic.getType());
|
||||||
|
sourceMethod = "inline-instantiation";
|
||||||
|
polymorphicEvents.add(declaredType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodName != null) {
|
||||||
|
if (varName != null && declaredType == null) {
|
||||||
|
for (String methodFqn : path) {
|
||||||
|
declaredType = getVariableDeclaredType(methodFqn, varName);
|
||||||
|
if (declaredType != null) {
|
||||||
|
sourceMethod = methodFqn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If it wasn't a variable, it might be a static method call (e.g., EventBuilder.buildEvent())
|
||||||
|
if (declaredType == null && varName.matches("^[A-Z].*")) {
|
||||||
|
org.eclipse.jdt.core.dom.TypeDeclaration staticTd = context.getTypeDeclaration(varName);
|
||||||
|
if (staticTd != null) {
|
||||||
|
declaredType = context.getFqn(staticTd);
|
||||||
|
sourceMethod = "static-call";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (declaredType != null) {
|
||||||
|
System.out.println("DEEP TRACE: " + sourceMethod + " " + (varName != null ? varName : "inline") + " -> " + declaredType);
|
||||||
|
List<String> typesToInspect = new ArrayList<>();
|
||||||
|
if ("inline-instantiation".equals(sourceMethod)) {
|
||||||
|
typesToInspect.add(declaredType);
|
||||||
|
} else {
|
||||||
|
typesToInspect.add(declaredType);
|
||||||
|
typesToInspect.addAll(context.getImplementations(declaredType));
|
||||||
|
}
|
||||||
|
System.out.println("DEEP TRACE IMPLS: " + typesToInspect);
|
||||||
|
|
||||||
|
for (String type : typesToInspect) {
|
||||||
|
Set<String> visited = new HashSet<>();
|
||||||
|
TypeDeclaration baseTd = context.getTypeDeclaration(type);
|
||||||
|
CompilationUnit cuToUse = null;
|
||||||
|
if (baseTd != null && baseTd.getRoot() instanceof CompilationUnit) {
|
||||||
|
cuToUse = (CompilationUnit) baseTd.getRoot();
|
||||||
|
} else {
|
||||||
|
String firstPathMethod = path.get(0);
|
||||||
|
String entryClassName = firstPathMethod.substring(0, firstPathMethod.lastIndexOf('.'));
|
||||||
|
TypeDeclaration entryTd = context.getTypeDeclaration(entryClassName);
|
||||||
|
if (entryTd != null && entryTd.getRoot() instanceof CompilationUnit) {
|
||||||
|
cuToUse = (CompilationUnit) entryTd.getRoot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> constants = resolveMethodReturnConstant(type, methodName, 0, visited, cuToUse);
|
||||||
|
System.out.println("DEEP TRACE RETURN: " + type + " -> " + constants);
|
||||||
|
for (String constant : constants) {
|
||||||
|
if (!polymorphicEvents.contains(constant)) {
|
||||||
|
polymorphicEvents.add(constant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// (e.g. it returned a field name like 'type', or nothing), we can scrape the resolvedValue string directly
|
||||||
|
// for string literals or enum-like constants.
|
||||||
|
boolean hasValidConstant = false;
|
||||||
|
for (String ev : polymorphicEvents) {
|
||||||
|
String val = ev.contains(".") ? ev.substring(ev.lastIndexOf('.') + 1) : ev;
|
||||||
|
if (val.equals(val.toUpperCase()) && val.length() > 2) {
|
||||||
|
hasValidConstant = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasValidConstant && resolvedValue.contains("(")) {
|
||||||
|
java.util.List<String> scraped = new java.util.ArrayList<>();
|
||||||
|
|
||||||
|
// Extract "STRING_LITERALS"
|
||||||
|
java.util.regex.Matcher m1 = java.util.regex.Pattern.compile("\"([^\"]+)\"").matcher(resolvedValue);
|
||||||
|
while (m1.find()) {
|
||||||
|
scraped.add(m1.group(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract ENUM_LIKE_CONSTANTS
|
||||||
|
java.util.regex.Matcher m2 = java.util.regex.Pattern.compile("\\b([A-Z_]{3,})\\b").matcher(resolvedValue);
|
||||||
|
while (m2.find()) {
|
||||||
|
if (!scraped.contains(m2.group(1))) {
|
||||||
|
scraped.add(m2.group(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scraped.isEmpty()) {
|
||||||
|
polymorphicEvents.clear();
|
||||||
|
polymorphicEvents.addAll(scraped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up any remaining invalid AST fallbacks (like 'type', 'event') if we found valid ones
|
||||||
|
if (polymorphicEvents.size() > 1) {
|
||||||
|
polymorphicEvents.removeIf(e -> {
|
||||||
|
String val = e.contains(".") ? e.substring(e.lastIndexOf('.') + 1) : e;
|
||||||
|
return !val.equals(val.toUpperCase()) || val.length() <= 2;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
List<String> newPolyEvents = new ArrayList<>();
|
||||||
|
for (String pe : polymorphicEvents) {
|
||||||
|
List<String> resolved = resolveClassConstantReturns(pe, context, null);
|
||||||
|
if (resolved != null && !resolved.isEmpty()) {
|
||||||
|
newPolyEvents.addAll(resolved);
|
||||||
|
} else {
|
||||||
|
newPolyEvents.add(pe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
polymorphicEvents = newPolyEvents;
|
||||||
|
|
||||||
|
if (!resolvedValue.equals(event) || !polymorphicEvents.isEmpty()) {
|
||||||
|
return TriggerPoint.builder()
|
||||||
|
.event(resolvedValue)
|
||||||
|
.className(tp.getClassName())
|
||||||
|
.methodName(tp.getMethodName())
|
||||||
|
.sourceFile(tp.getSourceFile())
|
||||||
|
.lineNumber(tp.getLineNumber())
|
||||||
|
.polymorphicEvents(polymorphicEvents)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getParameterIndex(String methodFqn, String paramName) {
|
||||||
|
if (methodFqn == null || !methodFqn.contains(".")) return -1;
|
||||||
|
String className = methodFqn.substring(0, methodFqn.lastIndexOf('.'));
|
||||||
|
String methodName = methodFqn.substring(methodFqn.lastIndexOf('.') + 1);
|
||||||
|
TypeDeclaration td = context.getTypeDeclaration(className);
|
||||||
|
if (td != null) {
|
||||||
|
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
||||||
|
if (md != null) {
|
||||||
|
for (int i = 0; i < md.parameters().size(); i++) {
|
||||||
|
SingleVariableDeclaration svd = (SingleVariableDeclaration) md.parameters().get(i);
|
||||||
|
if (svd.getName().getIdentifier().equals(paramName)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getVariableDeclaredType(String methodFqn, String varName) {
|
||||||
|
if (methodFqn == null || !methodFqn.contains(".")) return null;
|
||||||
|
String className = methodFqn.substring(0, methodFqn.lastIndexOf('.'));
|
||||||
|
String methodName = methodFqn.substring(methodFqn.lastIndexOf('.') + 1);
|
||||||
|
TypeDeclaration td = context.getTypeDeclaration(className);
|
||||||
|
if (td != null) {
|
||||||
|
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
||||||
|
if (md != null) {
|
||||||
|
for (Object pObj : md.parameters()) {
|
||||||
|
SingleVariableDeclaration svd = (SingleVariableDeclaration) pObj;
|
||||||
|
if (svd.getName().getIdentifier().equals(varName)) {
|
||||||
|
return svd.getType().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String[] foundType = new String[1];
|
||||||
|
if (md.getBody() != null) {
|
||||||
|
md.getBody().accept(new ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(VariableDeclarationStatement node) {
|
||||||
|
for (Object fragObj : node.fragments()) {
|
||||||
|
VariableDeclarationFragment frag = (VariableDeclarationFragment) fragObj;
|
||||||
|
if (frag.getName().getIdentifier().equals(varName)) {
|
||||||
|
foundType[0] = node.getType().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return foundType[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> resolveMethodReturnConstant(String className, String methodName, int depth, Set<String> visited, CompilationUnit contextCu) {
|
||||||
|
if (depth > 20) return Collections.emptyList();
|
||||||
|
String fqn = className + "." + methodName;
|
||||||
|
if (!visited.add(fqn)) return Collections.emptyList();
|
||||||
|
|
||||||
|
List<String> constants = new ArrayList<>();
|
||||||
|
TypeDeclaration tempTd = contextCu != null ? context.getTypeDeclaration(className, contextCu) : null;
|
||||||
|
if (tempTd == null) {
|
||||||
|
tempTd = context.getTypeDeclaration(className);
|
||||||
|
}
|
||||||
|
final TypeDeclaration td = tempTd;
|
||||||
|
if (td == null) {
|
||||||
|
System.out.println("DEEP TRACE FAILED TO FIND TD: " + className);
|
||||||
|
}
|
||||||
|
if (td != null) {
|
||||||
|
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
||||||
|
if (md != null && md.getBody() != null) {
|
||||||
|
md.getBody().accept(new ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(ReturnStatement node) {
|
||||||
|
Expression retExpr = node.getExpression();
|
||||||
|
if (retExpr != null) {
|
||||||
|
boolean handled = false;
|
||||||
|
if (retExpr instanceof MethodInvocation mi) {
|
||||||
|
// Follow delegation first
|
||||||
|
String called = resolveCalledMethod(mi);
|
||||||
|
System.out.println("DEEP TRACE RESOLVED CALLED: " + called);
|
||||||
|
if (called != null && called.contains(".")) {
|
||||||
|
if (visited.contains(called)) {
|
||||||
|
handled = true;
|
||||||
|
} else {
|
||||||
|
String cName = called.substring(0, called.lastIndexOf('.'));
|
||||||
|
String mName = called.substring(called.lastIndexOf('.') + 1);
|
||||||
|
|
||||||
|
TypeDeclaration targetTd = contextCu != null ? context.getTypeDeclaration(cName, contextCu) : context.getTypeDeclaration(cName);
|
||||||
|
if (targetTd == null) targetTd = context.getTypeDeclaration(cName);
|
||||||
|
|
||||||
|
if (targetTd != null && context.findMethodDeclaration(targetTd, mName, true) != null) {
|
||||||
|
List<String> delegationResult = resolveMethodReturnConstant(cName, mName, depth + 1, visited, contextCu);
|
||||||
|
constants.addAll(delegationResult);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!handled) {
|
||||||
|
String val = constantResolver.resolve(retExpr, context);
|
||||||
|
if (val != null) {
|
||||||
|
if (val.startsWith("ENUM_SET:")) {
|
||||||
|
for (String eVal : val.substring(9).split(",")) {
|
||||||
|
constants.add(eVal.substring(eVal.lastIndexOf('.') + 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
constants.add(val);
|
||||||
|
}
|
||||||
|
} else if (retExpr instanceof org.eclipse.jdt.core.dom.ClassInstanceCreation cic) {
|
||||||
|
constants.add(click.kamil.springstatemachineexporter.ast.common.AstUtils.extractSimpleTypeName(cic.getType()));
|
||||||
|
} else if (retExpr instanceof QualifiedName qn) {
|
||||||
|
constants.add(qn.toString());
|
||||||
|
} else if (retExpr instanceof SimpleName sn) {
|
||||||
|
List<String> consts = traceFieldInConstructors(td, sn.getIdentifier(), context, visited);
|
||||||
|
if (!consts.isEmpty()) {
|
||||||
|
constants.addAll(consts);
|
||||||
|
} else {
|
||||||
|
constants.add(sn.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visited.remove(fqn);
|
||||||
|
return constants;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> resolveClassConstantReturns(String className, click.kamil.springstatemachineexporter.ast.common.CodebaseContext context, CompilationUnit contextCu) {
|
||||||
|
TypeDeclaration td = contextCu != null ? context.getTypeDeclaration(className, contextCu) : context.getTypeDeclaration(className);
|
||||||
|
if (td == null) td = context.getTypeDeclaration(className);
|
||||||
|
if (td == null) return null;
|
||||||
|
|
||||||
|
final List<String> resolvedConstants = new ArrayList<>();
|
||||||
|
for (MethodDeclaration md : td.getMethods()) {
|
||||||
|
if (md.getBody() != null) {
|
||||||
|
md.getBody().accept(new ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(ReturnStatement node) {
|
||||||
|
if (node.getExpression() instanceof QualifiedName qn) {
|
||||||
|
resolvedConstants.add(qn.getName().getIdentifier());
|
||||||
|
} else if (node.getExpression() instanceof org.eclipse.jdt.core.dom.StringLiteral sl) {
|
||||||
|
resolvedConstants.add(sl.getLiteralValue());
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!resolvedConstants.isEmpty()) return resolvedConstants;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String traceLocalVariable(String methodFqn, String varName) {
|
||||||
|
if (methodFqn == null || !methodFqn.contains(".")) return null;
|
||||||
|
String className = methodFqn.substring(0, methodFqn.lastIndexOf('.'));
|
||||||
|
String methodName = methodFqn.substring(methodFqn.lastIndexOf('.') + 1);
|
||||||
|
TypeDeclaration td = context.getTypeDeclaration(className);
|
||||||
|
if (td != null) {
|
||||||
|
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
||||||
|
if (md != null && md.getBody() != null) {
|
||||||
|
final Expression[] initializer = new Expression[1];
|
||||||
|
md.getBody().accept(new ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(VariableDeclarationFragment node) {
|
||||||
|
if (node.getName().getIdentifier().equals(varName) && node.getInitializer() != null) {
|
||||||
|
initializer[0] = node.getInitializer();
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean visit(Assignment node) {
|
||||||
|
if (node.getLeftHandSide() instanceof SimpleName asn && asn.getIdentifier().equals(varName)) {
|
||||||
|
initializer[0] = node.getRightHandSide();
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (initializer[0] != null) {
|
||||||
|
Expression expr = traceVariable(initializer[0]);
|
||||||
|
if (expr instanceof MethodInvocation mi) {
|
||||||
|
// Unwrapper logic: If wrapper method is called, extract its arguments recursively
|
||||||
|
Expression innerMost = unwrapMethodInvocation(mi, 0);
|
||||||
|
if (innerMost instanceof MethodInvocation innerMi) {
|
||||||
|
if (innerMi.getExpression() instanceof SimpleName sn) {
|
||||||
|
return sn.getIdentifier() + "." + innerMi.getName().getIdentifier() + "()";
|
||||||
|
}
|
||||||
|
return innerMi.getName().getIdentifier() + "()";
|
||||||
|
}
|
||||||
|
if (innerMost instanceof SimpleName sn) {
|
||||||
|
return sn.getIdentifier();
|
||||||
|
}
|
||||||
|
return innerMost.toString();
|
||||||
|
}
|
||||||
|
if (expr instanceof SimpleName sn) {
|
||||||
|
return sn.getIdentifier();
|
||||||
|
}
|
||||||
|
return expr.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Expression unwrapMethodInvocation(MethodInvocation mi, int depth) {
|
||||||
|
if (depth > 5) return mi;
|
||||||
|
if (!mi.arguments().isEmpty()) {
|
||||||
|
Expression arg = (Expression) mi.arguments().get(0);
|
||||||
|
if (arg instanceof MethodInvocation innerMi) {
|
||||||
|
return unwrapMethodInvocation(innerMi, depth + 1);
|
||||||
|
}
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
return mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractContextMachineId(List<String> path, Map<String, List<CallEdge>> callGraph) {
|
||||||
|
for (String node : path) {
|
||||||
|
List<CallEdge> edges = callGraph.get(node);
|
||||||
|
if (edges != null) {
|
||||||
|
for (CallEdge edge : edges) {
|
||||||
|
String target = edge.getTargetMethod();
|
||||||
|
if (target != null && (target.contains(".restore") || target.contains(".read"))) {
|
||||||
|
// Persister signatures usually like: restore(stateMachine, contextObj)
|
||||||
|
if (edge.getArguments().size() >= 2) {
|
||||||
|
return edge.getArguments().get(1); // The contextObj / machineId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodDeclaration findEnclosingMethod(ASTNode node) {
|
||||||
|
ASTNode parent = node.getParent();
|
||||||
|
while (parent != null && !(parent instanceof MethodDeclaration)) {
|
||||||
|
parent = parent.getParent();
|
||||||
|
}
|
||||||
|
return (MethodDeclaration) parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, List<CallEdge>> buildCallGraph() {
|
||||||
graph = new HashMap<>();
|
graph = new HashMap<>();
|
||||||
for (CompilationUnit cu : context.getCompilationUnits()) {
|
for (CompilationUnit cu : context.getCompilationUnits()) {
|
||||||
cu.accept(new ASTVisitor() {
|
cu.accept(new ASTVisitor() {
|
||||||
@@ -188,7 +738,7 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
return allResolved;
|
return allResolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String resolveCalledMethod(MethodInvocation node) {
|
private String resolveCalledMethod(MethodInvocation node) {
|
||||||
Expression receiver = node.getExpression();
|
Expression receiver = node.getExpression();
|
||||||
String methodName = node.getName().getIdentifier();
|
String methodName = node.getName().getIdentifier();
|
||||||
|
|
||||||
@@ -357,4 +907,193 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> findPath(String start, String target, Map<String, List<CallEdge>> graph, Set<String> visited) {
|
||||||
|
if (start.equals(target)) return new ArrayList<>(List.of(start));
|
||||||
|
if (!visited.add(start)) return null; // Path-scoped cycle detection
|
||||||
|
|
||||||
|
List<CallEdge> neighbors = graph.get(start);
|
||||||
|
if (neighbors != null) {
|
||||||
|
for (CallEdge edge : neighbors) {
|
||||||
|
String neighbor = edge.getTargetMethod();
|
||||||
|
if (neighbor.equals(target) || isHeuristicMatch(neighbor, target)) {
|
||||||
|
visited.remove(start);
|
||||||
|
return new ArrayList<>(List.of(start, target));
|
||||||
|
}
|
||||||
|
List<String> path = findPath(neighbor, target, graph, visited);
|
||||||
|
if (path != null) {
|
||||||
|
path.add(0, start);
|
||||||
|
visited.remove(start);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Path search dead-end at {} when looking for {}", start, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
visited.remove(start);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHeuristicMatch(String neighbor, String target) {
|
||||||
|
if (neighbor.equals(target)) return true;
|
||||||
|
if (target.endsWith("." + neighbor)) return true;
|
||||||
|
if (neighbor.endsWith("." + target)) return true;
|
||||||
|
|
||||||
|
// If both are fully qualified (contain a dot) and didn't match above, they are definitely different methods
|
||||||
|
if (neighbor.contains(".") && target.contains(".")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String simpleTarget = target.contains(".") ? target.substring(target.lastIndexOf('.') + 1) : target;
|
||||||
|
String simpleNeighbor = neighbor.contains(".") ? neighbor.substring(neighbor.lastIndexOf('.') + 1) : neighbor;
|
||||||
|
return simpleNeighbor.equals(simpleTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeDeclaration findEnclosingType(ASTNode node) {
|
||||||
|
ASTNode parent = node.getParent();
|
||||||
|
while (parent != null && !(parent instanceof TypeDeclaration)) {
|
||||||
|
parent = parent.getParent();
|
||||||
|
}
|
||||||
|
return (TypeDeclaration) parent;
|
||||||
|
}
|
||||||
|
private Expression traceVariable(Expression expr) {
|
||||||
|
if (expr instanceof SimpleName sn) {
|
||||||
|
String varName = sn.getIdentifier();
|
||||||
|
MethodDeclaration enclosingMethod = findEnclosingMethod(expr);
|
||||||
|
if (enclosingMethod != null) {
|
||||||
|
final Expression[] initializer = new Expression[1];
|
||||||
|
enclosingMethod.accept(new ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(VariableDeclarationFragment node) {
|
||||||
|
if (node.getName().getIdentifier().equals(varName) && node.getInitializer() != null) {
|
||||||
|
initializer[0] = node.getInitializer();
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean visit(Assignment node) {
|
||||||
|
if (node.getLeftHandSide() instanceof SimpleName asn && asn.getIdentifier().equals(varName)) {
|
||||||
|
initializer[0] = node.getRightHandSide();
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (initializer[0] != null) {
|
||||||
|
return traceVariable(initializer[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> traceFieldInConstructors(TypeDeclaration td, String fieldName, CodebaseContext context, Set<String> visited) {
|
||||||
|
List<String> results = new ArrayList<>();
|
||||||
|
|
||||||
|
// 1. Check Field Declarations
|
||||||
|
for (org.eclipse.jdt.core.dom.FieldDeclaration fd : td.getFields()) {
|
||||||
|
for (Object fragObj : fd.fragments()) {
|
||||||
|
org.eclipse.jdt.core.dom.VariableDeclarationFragment frag = (org.eclipse.jdt.core.dom.VariableDeclarationFragment) fragObj;
|
||||||
|
if (frag.getName().getIdentifier().equals(fieldName) && frag.getInitializer() != null) {
|
||||||
|
Expression right = frag.getInitializer();
|
||||||
|
if (right instanceof MethodInvocation mi) {
|
||||||
|
String calledName = mi.getName().getIdentifier();
|
||||||
|
String targetClass = context.getFqn(td);
|
||||||
|
CompilationUnit cu = td.getRoot() instanceof CompilationUnit ? (CompilationUnit) td.getRoot() : null;
|
||||||
|
results.addAll(resolveMethodReturnConstant(targetClass, calledName, 0, new HashSet<>(visited), cu));
|
||||||
|
} else {
|
||||||
|
String val = constantResolver.resolve(right, context);
|
||||||
|
if (val != null) results.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
org.eclipse.jdt.core.dom.ASTVisitor assignmentVisitor = new org.eclipse.jdt.core.dom.ASTVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(Assignment node) {
|
||||||
|
Expression left = node.getLeftHandSide();
|
||||||
|
if ((left instanceof SimpleName && ((SimpleName) left).getIdentifier().equals(fieldName)) ||
|
||||||
|
(left instanceof FieldAccess && ((FieldAccess) left).getName().getIdentifier().equals(fieldName))) {
|
||||||
|
|
||||||
|
Expression right = node.getRightHandSide();
|
||||||
|
if (right instanceof MethodInvocation mi) {
|
||||||
|
String calledName = mi.getName().getIdentifier();
|
||||||
|
String targetClass = context.getFqn(td);
|
||||||
|
|
||||||
|
if (mi.getExpression() != null && mi.resolveMethodBinding() != null && mi.resolveMethodBinding().getDeclaringClass() != null) {
|
||||||
|
targetClass = mi.resolveMethodBinding().getDeclaringClass().getQualifiedName();
|
||||||
|
} else if (mi.getExpression() instanceof SimpleName) {
|
||||||
|
String exprName = ((SimpleName) mi.getExpression()).getIdentifier();
|
||||||
|
CompilationUnit cu = td.getRoot() instanceof CompilationUnit ? (CompilationUnit) td.getRoot() : null;
|
||||||
|
TypeDeclaration targetTd = context.resolveStaticImport(exprName, cu);
|
||||||
|
if (targetTd != null) {
|
||||||
|
targetClass = context.getFqn(targetTd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilationUnit cu = td.getRoot() instanceof CompilationUnit ? (CompilationUnit) td.getRoot() : null;
|
||||||
|
results.addAll(resolveMethodReturnConstant(targetClass, calledName, 0, new HashSet<>(visited), cu));
|
||||||
|
} else {
|
||||||
|
String val = constantResolver.resolve(right, context);
|
||||||
|
if (val != null) results.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean visit(ConstructorInvocation node) {
|
||||||
|
for (Object argObj : node.arguments()) {
|
||||||
|
Expression arg = (Expression) argObj;
|
||||||
|
String val = constantResolver.resolve(arg, context);
|
||||||
|
if (val != null) {
|
||||||
|
if (val.startsWith("ENUM_SET:")) {
|
||||||
|
for (String eVal : val.substring(9).split(",")) {
|
||||||
|
results.add(eVal.substring(eVal.lastIndexOf('.') + 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
results.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(SuperConstructorInvocation node) {
|
||||||
|
for (Object argObj : node.arguments()) {
|
||||||
|
Expression arg = (Expression) argObj;
|
||||||
|
String val = constantResolver.resolve(arg, context);
|
||||||
|
if (val != null) {
|
||||||
|
if (val.startsWith("ENUM_SET:")) {
|
||||||
|
for (String eVal : val.substring(9).split(",")) {
|
||||||
|
results.add(eVal.substring(eVal.lastIndexOf('.') + 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
results.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visit(node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Check Constructors
|
||||||
|
for (MethodDeclaration md : td.getMethods()) {
|
||||||
|
if (md.isConstructor() && md.getBody() != null) {
|
||||||
|
md.getBody().accept(assignmentVisitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Check Initializers
|
||||||
|
for (Object bodyDecl : td.bodyDeclarations()) {
|
||||||
|
if (bodyDecl instanceof org.eclipse.jdt.core.dom.Initializer init && init.getBody() != null) {
|
||||||
|
init.getBody().accept(assignmentVisitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package click.kamil.springstatemachineexporter.analysis.enricher.matching;
|
|
||||||
|
|
||||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
|
||||||
import click.kamil.springstatemachineexporter.model.Event;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
class HeuristicEventMatchingEngineTest {
|
|
||||||
|
|
||||||
private final HeuristicEventMatchingEngine engine = new HeuristicEventMatchingEngine();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldMatchExactFqn() {
|
|
||||||
Event smEvent = Event.of("PAY", "com.example.OrderEvents.PAY");
|
|
||||||
TriggerPoint triggerPoint = TriggerPoint.builder().event("com.example.OrderEvents.PAY").build();
|
|
||||||
|
|
||||||
assertThat(engine.matches(smEvent, triggerPoint)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldMatchEnumQualifierToFqn() {
|
|
||||||
Event smEvent = Event.of("PAY", "com.example.OrderEvents.PAY");
|
|
||||||
TriggerPoint triggerPoint = TriggerPoint.builder().event("OrderEvents.PAY").build();
|
|
||||||
|
|
||||||
assertThat(engine.matches(smEvent, triggerPoint)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldPreventCrossEnumContamination() {
|
|
||||||
Event smEvent = Event.of("PAY", "com.example.InvoiceEvents.PAY");
|
|
||||||
TriggerPoint triggerPoint = TriggerPoint.builder().event("OrderEvents.PAY").build();
|
|
||||||
|
|
||||||
assertThat(engine.matches(smEvent, triggerPoint)).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldPreventCrossEnumContaminationWithPolymorphicEvents() {
|
|
||||||
Event smEvent = Event.of("PAY", "com.example.InvoiceEvents.PAY");
|
|
||||||
TriggerPoint triggerPoint = TriggerPoint.builder().event("getType()").polymorphicEvents(List.of("OrderEvents.PAY")).build();
|
|
||||||
|
|
||||||
assertThat(engine.matches(smEvent, triggerPoint)).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldMatchPolymorphicEnumQualifierToFqn() {
|
|
||||||
Event smEvent = Event.of("PAY", "com.example.OrderEvents.PAY");
|
|
||||||
TriggerPoint triggerPoint = TriggerPoint.builder().event("getType()").polymorphicEvents(List.of("OrderEvents.PAY")).build();
|
|
||||||
|
|
||||||
assertThat(engine.matches(smEvent, triggerPoint)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldMatchRawStringToFqn() {
|
|
||||||
Event smEvent = Event.of("PAY", "com.example.OrderEvents.PAY");
|
|
||||||
TriggerPoint triggerPoint = TriggerPoint.builder().event("PAY").build();
|
|
||||||
|
|
||||||
assertThat(engine.matches(smEvent, triggerPoint)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldMatchRawStringToRawString() {
|
|
||||||
Event smEvent = Event.of("PAY", "PAY");
|
|
||||||
TriggerPoint triggerPoint = TriggerPoint.builder().event("PAY").build();
|
|
||||||
|
|
||||||
assertThat(engine.matches(smEvent, triggerPoint)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldMatchPolymorphicRawStringToFqn() {
|
|
||||||
Event smEvent = Event.of("PAY", "com.example.OrderEvents.PAY");
|
|
||||||
TriggerPoint triggerPoint = TriggerPoint.builder().event("getType()").polymorphicEvents(List.of("PAY")).build();
|
|
||||||
|
|
||||||
assertThat(engine.matches(smEvent, triggerPoint)).isTrue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
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.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
class BuilderLocalVariableTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldTraceLocalVariableInBuilderPattern(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent() {
|
|
||||||
OrderEvents e = OrderEvents.PAY;
|
|
||||||
RichOrderEvent event = new RichOrderEvent();
|
|
||||||
event.setType(e);
|
|
||||||
service.updateOrderState(event.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RichOrderEvent {
|
|
||||||
private OrderEvents type;
|
|
||||||
public void setType(OrderEvents type) { this.type = type; }
|
|
||||||
public OrderEvents getType() { return type; }
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
System.out.println("POLY EVENTS FOUND: " + chain.getTriggerPoint().getPolymorphicEvents());
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.containsExactlyInAnyOrder("OrderEvents.PAY");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,412 +0,0 @@
|
|||||||
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.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
class ConstructorInvocationTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldNotBlindlyAddAllConstructorArguments(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(RichOrderEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RichOrderEvent {
|
|
||||||
private OrderEvents type;
|
|
||||||
private String irrelevantInfo;
|
|
||||||
|
|
||||||
public RichOrderEvent() {
|
|
||||||
this(OrderEvents.PAY, "DEFAULT_INFO");
|
|
||||||
}
|
|
||||||
|
|
||||||
public RichOrderEvent(OrderEvents type, String info) {
|
|
||||||
this.type = type;
|
|
||||||
this.irrelevantInfo = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OrderEvents getType() { return type; }
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.contains("OrderEvents.PAY")
|
|
||||||
.doesNotContain("DEFAULT_INFO");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldHandleOverloadedConstructorsGracefully(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(RichOrderEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RichOrderEvent {
|
|
||||||
private OrderEvents type;
|
|
||||||
private String irrelevantInfo;
|
|
||||||
private int count;
|
|
||||||
|
|
||||||
public RichOrderEvent() {
|
|
||||||
this(OrderEvents.PAY, "DEFAULT_INFO");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overloaded constructor 1
|
|
||||||
public RichOrderEvent(OrderEvents type, String info) {
|
|
||||||
this.type = type;
|
|
||||||
this.irrelevantInfo = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overloaded constructor 2 (same number of arguments!)
|
|
||||||
public RichOrderEvent(String info, int count) {
|
|
||||||
this.irrelevantInfo = info;
|
|
||||||
this.count = count;
|
|
||||||
// type is not set here
|
|
||||||
}
|
|
||||||
|
|
||||||
public OrderEvents getType() { return type; }
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.contains("OrderEvents.PAY")
|
|
||||||
.doesNotContain("DEFAULT_INFO")
|
|
||||||
.doesNotContain("count");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldHandleChainedConstructorDelegationGracefully(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(RichOrderEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BaseEvent {
|
|
||||||
protected OrderEvents type;
|
|
||||||
public BaseEvent(OrderEvents type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RichOrderEvent extends BaseEvent {
|
|
||||||
public RichOrderEvent() {
|
|
||||||
this(OrderEvents.PAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RichOrderEvent(OrderEvents type) {
|
|
||||||
this(type, "DEFAULT_INFO");
|
|
||||||
}
|
|
||||||
|
|
||||||
public RichOrderEvent(OrderEvents type, String info) {
|
|
||||||
super(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public OrderEvents getType() { return type; }
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.contains("OrderEvents.PAY")
|
|
||||||
.doesNotContain("DEFAULT_INFO");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldHandleFieldAccessGracefully(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(RichOrderEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RichOrderEvent {
|
|
||||||
private OrderEvents type;
|
|
||||||
|
|
||||||
public RichOrderEvent() {
|
|
||||||
this(OrderEvents.PAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RichOrderEvent(OrderEvents type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OrderEvents getType() {
|
|
||||||
return this.type; // Specifically testing FieldAccess
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.contains("OrderEvents.PAY");
|
|
||||||
}
|
|
||||||
@Test
|
|
||||||
void shouldTraceThroughWrappedConstructorArguments(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(RichOrderEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RichOrderEvent {
|
|
||||||
private OrderEvents type;
|
|
||||||
|
|
||||||
public RichOrderEvent() {
|
|
||||||
this(Objects.requireNonNull(OrderEvents.PAY));
|
|
||||||
}
|
|
||||||
|
|
||||||
public RichOrderEvent(OrderEvents type) {
|
|
||||||
this((OrderEvents) type, "DEFAULT_INFO");
|
|
||||||
}
|
|
||||||
|
|
||||||
public RichOrderEvent(OrderEvents type, String info) {
|
|
||||||
this.type = Objects.requireNonNull(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public OrderEvents getType() { return type; }
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.contains("OrderEvents.PAY");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldTraceThroughComplexOverloadedConstructors(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(EnterpriseEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class EnterpriseEvent {
|
|
||||||
private OrderEvents type;
|
|
||||||
private String info;
|
|
||||||
|
|
||||||
public EnterpriseEvent() {
|
|
||||||
this(OrderEvents.PAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Matches by parameter count but wrong type!
|
|
||||||
public EnterpriseEvent(String info) {
|
|
||||||
this.info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EnterpriseEvent(OrderEvents type) {
|
|
||||||
this("info", type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Target of previous constructor
|
|
||||||
public EnterpriseEvent(String info, OrderEvents type) {
|
|
||||||
this(type, info, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final destination
|
|
||||||
public EnterpriseEvent(OrderEvents type, String info, Object extra) {
|
|
||||||
this.type = type;
|
|
||||||
this.info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OrderEvents getType() { return type; }
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.contains("OrderEvents.PAY");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
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.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
class ConstructorLocalVariableTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldTraceLocalVariableInConstructor(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(RichOrderEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RichOrderEvent {
|
|
||||||
private OrderEvents type;
|
|
||||||
|
|
||||||
public RichOrderEvent() {
|
|
||||||
OrderEvents e = OrderEvents.PAY;
|
|
||||||
this.type = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OrderEvents getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.containsExactlyInAnyOrder("OrderEvents.PAY");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,185 +18,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
@Tag("heuristic_guess_paths_and_scrape_regex_replace_with_data_flow_analysis")
|
@Tag("heuristic_guess_paths_and_scrape_regex_replace_with_data_flow_analysis")
|
||||||
class HeuristicCallGraphEngineTest {
|
class HeuristicCallGraphEngineTest {
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldResolveLocalSetterAndSwitchExpressionPolymorphism(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderService {
|
|
||||||
public void updateOrderState(String vv) {
|
|
||||||
StateMachine sm = new StateMachine();
|
|
||||||
MysteryPayload a = new MysteryPayload();
|
|
||||||
a.setType(my_func(vv));
|
|
||||||
sm.sendEvent(a.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
private OrderEvents my_func(String q) {
|
|
||||||
return switch (q) {
|
|
||||||
case "a" -> OrderEvents.A8;
|
|
||||||
case "b" -> OrderEvents.A133;
|
|
||||||
default -> throw new IllegalArgumentException("Unknown");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { A8, A133 }
|
|
||||||
|
|
||||||
class MysteryPayload {
|
|
||||||
private OrderEvents type;
|
|
||||||
public void setType(OrderEvents type) { this.type = type; }
|
|
||||||
public OrderEvents getType() { return type; }
|
|
||||||
}
|
|
||||||
|
|
||||||
class StateMachine {
|
|
||||||
public void sendEvent(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderService.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.StateMachine")
|
|
||||||
.methodName("sendEvent")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
|
|
||||||
System.out.println("Resolved poly events: " + chain.getTriggerPoint().getPolymorphicEvents());
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.containsExactlyInAnyOrder("OrderEvents.A8", "OrderEvents.A133");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldResolveOldStyleSwitchStatementPolymorphism(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderService {
|
|
||||||
public void updateOrderState(String vv) {
|
|
||||||
StateMachine sm = new StateMachine();
|
|
||||||
sm.sendEvent(getEventFromOldSwitch(vv));
|
|
||||||
}
|
|
||||||
|
|
||||||
private OrderEvents getEventFromOldSwitch(String q) {
|
|
||||||
switch (q) {
|
|
||||||
case "a": return OrderEvents.A8;
|
|
||||||
case "b":
|
|
||||||
case "c": return OrderEvents.A133;
|
|
||||||
default: return OrderEvents.PAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { A8, A133, PAY }
|
|
||||||
|
|
||||||
class StateMachine {
|
|
||||||
public void sendEvent(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderService.java"), source);
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder().className("com.example.OrderService").methodName("updateOrderState").build();
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder().className("com.example.StateMachine").methodName("sendEvent").event("event").build();
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.containsExactlyInAnyOrder("OrderEvents.A8", "OrderEvents.A133", "OrderEvents.PAY");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldResolveMultiValueSwitchExpressionPolymorphism(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderService {
|
|
||||||
public void updateOrderState(String vv) {
|
|
||||||
StateMachine sm = new StateMachine();
|
|
||||||
sm.sendEvent(getEventMultiValue(vv));
|
|
||||||
}
|
|
||||||
|
|
||||||
private OrderEvents getEventMultiValue(String q) {
|
|
||||||
return switch (q) {
|
|
||||||
case "a", "b" -> OrderEvents.A8;
|
|
||||||
case "c" -> OrderEvents.A133;
|
|
||||||
default -> OrderEvents.PAY;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { A8, A133, PAY }
|
|
||||||
|
|
||||||
class StateMachine {
|
|
||||||
public void sendEvent(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderService.java"), source);
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder().className("com.example.OrderService").methodName("updateOrderState").build();
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder().className("com.example.StateMachine").methodName("sendEvent").event("event").build();
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.containsExactlyInAnyOrder("OrderEvents.A8", "OrderEvents.A133", "OrderEvents.PAY");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldResolveSwitchExpressionWithBlockAndYieldPolymorphism(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderService {
|
|
||||||
public void updateOrderState(String vv) {
|
|
||||||
StateMachine sm = new StateMachine();
|
|
||||||
sm.sendEvent(getEventWithYield(vv));
|
|
||||||
}
|
|
||||||
|
|
||||||
private OrderEvents getEventWithYield(String q) {
|
|
||||||
return switch (q) {
|
|
||||||
case "a" -> {
|
|
||||||
System.out.println("Processing a");
|
|
||||||
yield OrderEvents.A8;
|
|
||||||
}
|
|
||||||
case "b" -> { yield OrderEvents.A133; }
|
|
||||||
default -> OrderEvents.PAY;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { A8, A133, PAY }
|
|
||||||
|
|
||||||
class StateMachine {
|
|
||||||
public void sendEvent(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderService.java"), source);
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder().className("com.example.OrderService").methodName("updateOrderState").build();
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder().className("com.example.StateMachine").methodName("sendEvent").event("event").build();
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.containsExactlyInAnyOrder("OrderEvents.A8", "OrderEvents.A133", "OrderEvents.PAY");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldFindCallChainWithLambdaMethodReference(@TempDir Path tempDir) throws IOException {
|
void shouldFindCallChainWithLambdaMethodReference(@TempDir Path tempDir) throws IOException {
|
||||||
String source = """
|
String source = """
|
||||||
@@ -471,63 +292,6 @@ class HeuristicCallGraphEngineTest {
|
|||||||
.containsExactlyInAnyOrder("OrderEvents.CANCELLED", "OrderEvents.RECEIVED");
|
.containsExactlyInAnyOrder("OrderEvents.CANCELLED", "OrderEvents.RECEIVED");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldResolveTernaryAndStringPolymorphicReturns() throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent() {
|
|
||||||
service.updateOrderState(new MysteryPayload().getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(Object event) {
|
|
||||||
// sendEvent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MysteryPayload {
|
|
||||||
public Object getType() {
|
|
||||||
int a = 5;
|
|
||||||
if (a > 10) {
|
|
||||||
return "RAW_STRING_EVENT";
|
|
||||||
}
|
|
||||||
return a > 5 ? OrderEvents.ABCD : OrderEvents.PAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { ABCD, PAY }
|
|
||||||
""";
|
|
||||||
Path tempDir = Files.createTempDirectory("callgraph_test_ternary_string");
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.as("Resolved event was: " + chain.getTriggerPoint().getEvent())
|
|
||||||
.containsExactlyInAnyOrder("OrderEvents.ABCD", "OrderEvents.PAY", "RAW_STRING_EVENT");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldUnwrapDeepMethodWrappers() throws IOException {
|
void shouldUnwrapDeepMethodWrappers() throws IOException {
|
||||||
String source = """
|
String source = """
|
||||||
|
|||||||
@@ -1,122 +0,0 @@
|
|||||||
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.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
class LocalVariableTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldTraceLocalVariableInGetter(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(RichOrderEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RichOrderEvent {
|
|
||||||
public OrderEvents getType() {
|
|
||||||
OrderEvents e = OrderEvents.PAY;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.contains("OrderEvents.PAY")
|
|
||||||
.doesNotContain("e"); // Should not blindly add the variable name
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldTraceMultipleAssignments(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(RichOrderEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RichOrderEvent {
|
|
||||||
public OrderEvents getType() {
|
|
||||||
OrderEvents e = null;
|
|
||||||
if (System.currentTimeMillis() % 2 == 0) {
|
|
||||||
e = OrderEvents.PAY;
|
|
||||||
} else {
|
|
||||||
e = OrderEvents.CANCEL;
|
|
||||||
}
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY, CANCEL }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.containsExactlyInAnyOrder("OrderEvents.PAY", "OrderEvents.CANCEL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
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.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
class ReturnStatementTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldHandleAssignmentInReturn(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(RichOrderEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RichOrderEvent {
|
|
||||||
private OrderEvents type;
|
|
||||||
public OrderEvents getType() {
|
|
||||||
return this.type = OrderEvents.PAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.containsExactlyInAnyOrder("OrderEvents.PAY");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
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.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
class SuperMethodInvocationTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldHandleSuperMethodInvocation(@TempDir Path tempDir) throws IOException {
|
|
||||||
String source = """
|
|
||||||
package com.example;
|
|
||||||
public class OrderController {
|
|
||||||
private OrderService service;
|
|
||||||
public void processOrderEvent(DerivedEvent domainEvent) {
|
|
||||||
service.updateOrderState(domainEvent.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrderService {
|
|
||||||
public void updateOrderState(OrderEvents event) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BaseEvent {
|
|
||||||
public OrderEvents getType() {
|
|
||||||
return OrderEvents.PAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DerivedEvent extends BaseEvent {
|
|
||||||
public OrderEvents getType() {
|
|
||||||
return super.getType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OrderEvents { PAY }
|
|
||||||
""";
|
|
||||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
|
||||||
|
|
||||||
CodebaseContext context = new CodebaseContext();
|
|
||||||
context.scan(tempDir);
|
|
||||||
|
|
||||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
|
||||||
|
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
|
||||||
.className("com.example.OrderController")
|
|
||||||
.methodName("processOrderEvent")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
|
||||||
.className("com.example.OrderService")
|
|
||||||
.methodName("updateOrderState")
|
|
||||||
.event("event")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
|
||||||
|
|
||||||
assertThat(chains).hasSize(1);
|
|
||||||
CallChain chain = chains.get(0);
|
|
||||||
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
|
|
||||||
.contains("OrderEvents.PAY");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -574,114 +574,6 @@
|
|||||||
"targetState" : "START",
|
"targetState" : "START",
|
||||||
"event" : "AUDIT_EVENT"
|
"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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -709,60 +601,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -790,168 +628,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.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" : null
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -979,87 +655,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -1087,87 +682,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.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" : null
|
|
||||||
},
|
|
||||||
"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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -1195,141 +709,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.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" : null
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -1357,141 +736,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.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" : null
|
|
||||||
},
|
|
||||||
"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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
|
|||||||
@@ -574,114 +574,6 @@
|
|||||||
"targetState" : "START",
|
"targetState" : "START",
|
||||||
"event" : "AUDIT_EVENT"
|
"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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -709,60 +601,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -790,168 +628,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.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" : null
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -979,87 +655,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -1087,87 +682,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.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" : null
|
|
||||||
},
|
|
||||||
"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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -1195,141 +709,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.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" : null
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -1357,141 +736,6 @@
|
|||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : 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.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" : null
|
|
||||||
},
|
|
||||||
"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.FallbackQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.ProfiledQuirkService.doQuirk" ],
|
|
||||||
"triggerPoint" : {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"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.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" : null
|
|
||||||
},
|
|
||||||
"contextMachineId" : null,
|
|
||||||
"matchedTransitions" : null
|
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
|
|||||||
@@ -191,7 +191,7 @@
|
|||||||
"stateMachineId" : null,
|
"stateMachineId" : null,
|
||||||
"sourceState" : null,
|
"sourceState" : null,
|
||||||
"lineNumber" : 13,
|
"lineNumber" : 13,
|
||||||
"polymorphicEvents" : [ "OrderEvents.PAY" ]
|
"polymorphicEvents" : [ "PAY" ]
|
||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : [ {
|
"matchedTransitions" : [ {
|
||||||
@@ -222,7 +222,7 @@
|
|||||||
"stateMachineId" : null,
|
"stateMachineId" : null,
|
||||||
"sourceState" : null,
|
"sourceState" : null,
|
||||||
"lineNumber" : 13,
|
"lineNumber" : 13,
|
||||||
"polymorphicEvents" : [ "OrderEvents.FULFILL" ]
|
"polymorphicEvents" : [ "FULFILL" ]
|
||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : [ {
|
"matchedTransitions" : [ {
|
||||||
@@ -253,7 +253,7 @@
|
|||||||
"stateMachineId" : null,
|
"stateMachineId" : null,
|
||||||
"sourceState" : null,
|
"sourceState" : null,
|
||||||
"lineNumber" : 13,
|
"lineNumber" : 13,
|
||||||
"polymorphicEvents" : [ "OrderEvents.CANCEL" ]
|
"polymorphicEvents" : [ "CANCEL" ]
|
||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : [ {
|
"matchedTransitions" : [ {
|
||||||
@@ -284,7 +284,7 @@
|
|||||||
"stateMachineId" : null,
|
"stateMachineId" : null,
|
||||||
"sourceState" : null,
|
"sourceState" : null,
|
||||||
"lineNumber" : 17,
|
"lineNumber" : 17,
|
||||||
"polymorphicEvents" : [ "OrderEvents.PAY" ]
|
"polymorphicEvents" : [ "PAY" ]
|
||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : [ {
|
"matchedTransitions" : [ {
|
||||||
@@ -315,7 +315,7 @@
|
|||||||
"stateMachineId" : null,
|
"stateMachineId" : null,
|
||||||
"sourceState" : null,
|
"sourceState" : null,
|
||||||
"lineNumber" : 13,
|
"lineNumber" : 13,
|
||||||
"polymorphicEvents" : [ "OrderEvents.PAY" ]
|
"polymorphicEvents" : [ "PAY" ]
|
||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : [ {
|
"matchedTransitions" : [ {
|
||||||
@@ -346,7 +346,7 @@
|
|||||||
"stateMachineId" : null,
|
"stateMachineId" : null,
|
||||||
"sourceState" : null,
|
"sourceState" : null,
|
||||||
"lineNumber" : 13,
|
"lineNumber" : 13,
|
||||||
"polymorphicEvents" : [ "OrderEvents.PAY" ]
|
"polymorphicEvents" : [ "PAY" ]
|
||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : [ {
|
"matchedTransitions" : [ {
|
||||||
@@ -451,10 +451,14 @@
|
|||||||
"stateMachineId" : null,
|
"stateMachineId" : null,
|
||||||
"sourceState" : null,
|
"sourceState" : null,
|
||||||
"lineNumber" : 13,
|
"lineNumber" : 13,
|
||||||
"polymorphicEvents" : [ ]
|
"polymorphicEvents" : [ "FULFILL" ]
|
||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : null
|
"matchedTransitions" : [ {
|
||||||
|
"sourceState" : "OrderStates.PAID",
|
||||||
|
"targetState" : "OrderStates.FULFILLED",
|
||||||
|
"event" : "OrderEvents.FULFILL"
|
||||||
|
} ]
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -478,10 +482,14 @@
|
|||||||
"stateMachineId" : null,
|
"stateMachineId" : null,
|
||||||
"sourceState" : null,
|
"sourceState" : null,
|
||||||
"lineNumber" : 13,
|
"lineNumber" : 13,
|
||||||
"polymorphicEvents" : [ ]
|
"polymorphicEvents" : [ "CANCEL" ]
|
||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : null
|
"matchedTransitions" : [ {
|
||||||
|
"sourceState" : "OrderStates.SUBMITTED",
|
||||||
|
"targetState" : "OrderStates.CANCELED",
|
||||||
|
"event" : "OrderEvents.CANCEL"
|
||||||
|
} ]
|
||||||
}, {
|
}, {
|
||||||
"entryPoint" : {
|
"entryPoint" : {
|
||||||
"type" : "REST",
|
"type" : "REST",
|
||||||
@@ -505,7 +513,7 @@
|
|||||||
"stateMachineId" : null,
|
"stateMachineId" : null,
|
||||||
"sourceState" : null,
|
"sourceState" : null,
|
||||||
"lineNumber" : 21,
|
"lineNumber" : 21,
|
||||||
"polymorphicEvents" : [ "OrderEvents.ABCD" ]
|
"polymorphicEvents" : [ "ABCD" ]
|
||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : [ {
|
"matchedTransitions" : [ {
|
||||||
@@ -536,7 +544,7 @@
|
|||||||
"stateMachineId" : null,
|
"stateMachineId" : null,
|
||||||
"sourceState" : null,
|
"sourceState" : null,
|
||||||
"lineNumber" : 21,
|
"lineNumber" : 21,
|
||||||
"polymorphicEvents" : [ "OrderEvents.ABCD", "OrderEvents.PAY" ]
|
"polymorphicEvents" : [ "ABCD", "PAY" ]
|
||||||
},
|
},
|
||||||
"contextMachineId" : null,
|
"contextMachineId" : null,
|
||||||
"matchedTransitions" : [ {
|
"matchedTransitions" : [ {
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ public class MysteryPayload implements CustomCodeEventInterface {
|
|||||||
@Override
|
@Override
|
||||||
public OrderEvents resolveEventCode() {
|
public OrderEvents resolveEventCode() {
|
||||||
int a = (int) (Math.random() * 10);
|
int a = (int) (Math.random() * 10);
|
||||||
return a > 5 ? OrderEvents.ABCD : OrderEvents.PAY;
|
if (a > 5) {
|
||||||
|
return OrderEvents.ABCD;
|
||||||
|
} else {
|
||||||
|
return OrderEvents.PAY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user