This commit is contained in:
2026-07-06 19:13:12 +02:00
parent 6472f01026
commit 0a8f9720c9
29 changed files with 578 additions and 536 deletions

View File

@@ -43,9 +43,11 @@ public class SymbolicPathValueEstimator implements PathValueEstimator {
click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver resolver = new click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver();
String callerVal = resolver.resolve(caller, context);
if (callerVal != null && !callerVal.isEmpty()) {
addValue(collectedConstants, callerVal);
if (caller != null) {
String callerVal = resolver.resolve(caller, context);
if (callerVal != null && !callerVal.isEmpty()) {
addValue(collectedConstants, callerVal);
}
}
String argVal = resolver.resolve(arg, context);

View File

@@ -143,11 +143,14 @@ public class DynamicClasspathResolver {
}
protected void runProcess(ProcessBuilder pb) throws IOException, InterruptedException {
pb.redirectErrorStream(true);
pb.redirectOutput(ProcessBuilder.Redirect.DISCARD);
Process p = pb.start();
p.waitFor();
}
protected String runProcessAndGetOutput(ProcessBuilder pb) throws IOException, InterruptedException {
pb.redirectErrorStream(true);
Process p = pb.start();
StringBuilder out = new StringBuilder();
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {

View File

@@ -76,7 +76,7 @@ public class SpringContextScanner extends ASTVisitor {
.isPrimary(hasPrimaryMethod(methodBinding, node))
.qualifiers(extractQualifiers(methodBinding))
.order(extractOrder(methodBinding))
.declaringClassFqn(methodBinding.getDeclaringClass().getQualifiedName())
.declaringClassFqn(methodBinding.getDeclaringClass() != null ? methodBinding.getDeclaringClass().getQualifiedName() : null)
.factoryMethodName(node.getName().getIdentifier())
.build();

View File

@@ -210,7 +210,7 @@ public class AstTransitionParser {
Expression resolved = resolveArg((Expression) arg, argsMap);
t.getTargetStates().add(context.resolveState(resolved, cu));
});
case "event" -> {
case "event" -> {
Expression resolved = resolveArg((Expression) args.get(0), argsMap);
String eventValue = constantResolver.resolve(resolved, context);
if (eventValue != null) {
@@ -239,15 +239,31 @@ public class AstTransitionParser {
} else {
t.setEvent(Event.of(QuotedExpression.of(resolved).toStringWithoutQuotes()));
}
if (args.size() > 1) {
Expression actionArg = resolveArg((Expression) args.get(1), argsMap);
parseAction(actionArg, t, cu, context);
}
}
case "guard", "guardExpression" -> {
Expression resolved = resolveArg((Expression) args.get(0), argsMap);
parseGuard(resolved, t, cu, context);
}
case "guards" -> {
args.forEach(arg -> {
Expression resolved = resolveArg((Expression) arg, argsMap);
parseGuard(resolved, t, cu, context);
});
}
case "action" -> {
Expression resolved = resolveArg((Expression) args.get(0), argsMap);
parseAction(resolved, t, cu, context);
}
case "actions" -> {
args.forEach(arg -> {
Expression resolved = resolveArg((Expression) arg, argsMap);
parseAction(resolved, t, cu, context);
});
}
case "timer", "timerOnce" -> {
Expression resolved = resolveArg((Expression) args.get(0), argsMap);
t.setEvent(Event.of(methodName + "(" + resolved.toString() + ")", methodName + "(" + resolved.toString() + ")"));
@@ -521,7 +537,7 @@ public class AstTransitionParser {
TypeDeclaration td = findEnclosingType(quotedExpr.getExpression());
String fqn = td != null ? context.getFqn(td) : null;
String sourceFile = fqn != null ? context.getRelativePath(fqn) : null;
t.setGuard(Guard.of(quotedExpr.toStringWithoutQuotes(), isLambdaOrAnonymous(quotedExpr.getExpression()), internalLogic, lineNumber, fqn, sourceFile));
t.getGuards().add(Guard.of(quotedExpr.toStringWithoutQuotes(), isLambdaOrAnonymous(quotedExpr.getExpression()), internalLogic, lineNumber, fqn, sourceFile));
}
}

View File

@@ -107,13 +107,19 @@ public class Dot implements StateMachineExporter {
}
}
// Guard
if (t.getGuard() != null && !t.getGuard().expression().isBlank()) {
// Guards
if (t.getGuards() != null && !t.getGuards().isEmpty()) {
if (!label.isEmpty())
label.append(" ");
String guardText = options.isUseLambdaGuards() && t.getGuard().isLambda() ? "λ"
: escapeDotString(t.getGuard().expression().replaceAll("[\\n\\r]+", " ").replaceAll("\\s{2,}", " ").trim());
label.append("[").append(guardText).append("]");
label.append("[");
for (int i = 0; i < t.getGuards().size(); i++) {
if (i > 0) label.append(" && ");
var guard = t.getGuards().get(i);
String guardText = options.isUseLambdaGuards() && guard.isLambda() ? "λ"
: escapeDotString(guard.expression().replaceAll("[\\n\\r]+", " ").replaceAll("\\s{2,}", " ").trim());
label.append(guardText);
}
label.append("]");
}
// Actions

View File

@@ -203,13 +203,20 @@ public class PlantUml implements StateMachineExporter {
parts.add(eventStr);
}
}
if (t.getGuard() != null) {
String g = t.getGuard().expression();
if (options.isUseLambdaGuards() && t.getGuard().isLambda()) {
parts.add("[" + LAMBDA + "]");
} else {
parts.add("[" + g.replaceAll("[\\n\\r]+", " ").replaceAll("\\s{2,}", " ").trim() + "]");
if (t.getGuards() != null && !t.getGuards().isEmpty()) {
StringBuilder guardsBuilder = new StringBuilder();
guardsBuilder.append("[");
for (int i = 0; i < t.getGuards().size(); i++) {
if (i > 0) guardsBuilder.append(" && ");
var guard = t.getGuards().get(i);
if (options.isUseLambdaGuards() && guard.isLambda()) {
guardsBuilder.append(LAMBDA);
} else {
guardsBuilder.append(guard.expression().replaceAll("[\\n\\r]+", " ").replaceAll("\\s{2,}", " ").trim());
}
}
guardsBuilder.append("]");
parts.add(guardsBuilder.toString());
}
if (t.getActions() != null && !t.getActions().isEmpty()) {
parts.add("/ " + t.getActions().stream()

View File

@@ -102,12 +102,20 @@ public class Scxml implements StateMachineExporter {
}
private static String getGuardText(Transition t, boolean useLambdaGuards) {
if (t.getGuard() == null || t.getGuard().expression().isBlank())
if (t.getGuards() == null || t.getGuards().isEmpty())
return "";
if (useLambdaGuards && t.getGuard().isLambda()) {
return LAMBDA;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < t.getGuards().size(); i++) {
if (i > 0) sb.append(" && ");
var guard = t.getGuards().get(i);
if (useLambdaGuards && guard.isLambda()) {
sb.append(LAMBDA);
} else {
sb.append(guard.expression().replaceAll("[\\n\\r]+", " ").replaceAll("\\s{2,}", " ").trim());
}
}
return t.getGuard().expression().replaceAll("[\\n\\r]+", " ").replaceAll("\\s{2,}", " ").trim();
return sb.toString();
}
private static String escapeXml(String s) {

View File

@@ -16,7 +16,7 @@ public class Transition {
private List<State> targetStates = new ArrayList<>();
private Event event;
private Guard guard;
private List<Guard> guards = new ArrayList<>();
private List<Action> actions = new ArrayList<>();
private Integer order = null; // optional order for withChoice or withJunction