diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java index d37c0a1..2241112 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java @@ -194,20 +194,38 @@ public class TransitionLinkerEnricher implements AnalysisEnricher { } } + private final java.util.Map simplifyCache = new java.util.HashMap<>(); + private final java.util.Map guardedCache = new java.util.HashMap<>(); + private static final java.util.regex.Pattern SUFFIX_PATTERN = java.util.regex.Pattern.compile("(?i)(.+)(Event|Action|Transition|Command)(s)?$"); + private static final java.util.regex.Pattern FQN_PATTERN = java.util.regex.Pattern.compile("^.*\\.([A-Z0-9_]+)$"); + private String simplify(String name) { if (name == null) return null; + if (simplifyCache.containsKey(name)) return simplifyCache.get(name); + // Strip common suffixes - String simplified = name.replaceAll("(?i)(.+)(Event|Action|Transition|Command)(s)?$", "$1"); + String simplified = SUFFIX_PATTERN.matcher(name).replaceAll("$1"); if (simplified.isEmpty()) { simplified = name; } // Simplify full identifiers to just the last part (enum name) - simplified = simplified.replaceAll("^.*\\.([A-Z0-9_]+)$", "$1"); - // For remaining full caps with underscores (like EVENT_X), keep as is or try to simplify + simplified = FQN_PATTERN.matcher(simplified).replaceAll("$1"); + + simplifyCache.put(name, simplified); return simplified; } private boolean isGuardedContains(String smEvent, String triggerEvent) { + if (smEvent == null || triggerEvent == null) return false; + String cacheKey = smEvent + "|" + triggerEvent; + if (guardedCache.containsKey(cacheKey)) return guardedCache.get(cacheKey); + + boolean result = calculateGuardedContains(smEvent, triggerEvent); + guardedCache.put(cacheKey, result); + return result; + } + + private boolean calculateGuardedContains(String smEvent, String triggerEvent) { // Only fire if it looks like a simple identifier (no spaces, no parens) // Prevents unresolved AST nodes (e.g. "event.getPayload()") from accidentally matching "Event" if (smEvent.contains(" ") || smEvent.contains("(") || smEvent.contains(")") || @@ -225,7 +243,7 @@ public class TransitionLinkerEnricher implements AnalysisEnricher { // Guard: If the matching part is very short (< 4 chars), it must be bounded by word separators // to avoid matching completely unrelated words (e.g., "PAY" matching "PAYMENT" or "E" matching "UPDATE") if (shorter.length() < 4) { - return longer.matches(".*(^|_|-)" + shorter + "(_|-|$).*"); + return longer.matches(".*(^|_|-)" + java.util.regex.Pattern.quote(shorter) + "(_|-|$).*"); } // For longer strings, a straight contains is usually safe enough return true; diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/matching/HeuristicEventMatchingEngine.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/matching/HeuristicEventMatchingEngine.java index 2bc8e13..b996a7b 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/matching/HeuristicEventMatchingEngine.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/matching/HeuristicEventMatchingEngine.java @@ -87,8 +87,22 @@ public class HeuristicEventMatchingEngine implements EventMatchingEngine { return isGuardedContains(smEvent, triggerEvent); } + private final java.util.Map simplifyCache = new java.util.HashMap<>(); + private final java.util.Map guardedCache = new java.util.HashMap<>(); + private static final java.util.regex.Pattern SUFFIX_PATTERN = java.util.regex.Pattern.compile("(?i)(.+)(Event|Action|Transition|Command)(s)?$"); + private static final java.util.regex.Pattern FQN_PATTERN = java.util.regex.Pattern.compile("^.*\\.([A-Z0-9_]+)$"); + private boolean isGuardedContains(String smEvent, String triggerEvent) { if (smEvent == null || triggerEvent == null) return false; + String cacheKey = smEvent + "|" + triggerEvent; + if (guardedCache.containsKey(cacheKey)) return guardedCache.get(cacheKey); + + boolean result = calculateGuardedContains(smEvent, triggerEvent); + guardedCache.put(cacheKey, result); + return result; + } + + private boolean calculateGuardedContains(String smEvent, String triggerEvent) { // Only fire if it looks like a simple identifier (no spaces, no parens) // Prevents unresolved AST nodes (e.g. "event.getPayload()") from accidentally matching "Event" if (smEvent.contains(" ") || smEvent.contains("(") || smEvent.contains(")") || @@ -137,11 +151,15 @@ public class HeuristicEventMatchingEngine implements EventMatchingEngine { private String simplify(String name) { if (name == null) return null; - String simplified = name.replaceAll("(?i)(.+)(Event|Action|Transition|Command)(s)?$", "$1"); + if (simplifyCache.containsKey(name)) return simplifyCache.get(name); + + String simplified = SUFFIX_PATTERN.matcher(name).replaceAll("$1"); if (simplified.isEmpty()) { simplified = name; } - simplified = simplified.replaceAll("^.*\\.([A-Z0-9_]+)$", "$1"); + simplified = FQN_PATTERN.matcher(simplified).replaceAll("$1"); + + simplifyCache.put(name, simplified); return simplified; } }