From 613dfffd53eee4ddd812e42c2647026b22b49bea Mon Sep 17 00:00:00 2001 From: Kamil Patryk Kozakowski Date: Sun, 12 Jul 2026 05:54:45 +0200 Subject: [PATCH] Align enum rawName with fn-form labels during canonicalization. Derive transition and state rawName from package-canonical fullIdentifier so JSON exports stay consistent when bare constants or mismatched short forms appear in source. Co-authored-by: Cursor --- .../resolver/MachineEnumCanonicalizer.java | 34 +++++++++++++++++-- .../MachineEnumCanonicalizerTest.java | 23 +++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/MachineEnumCanonicalizer.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/MachineEnumCanonicalizer.java index a0c2d9e..2acd684 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/MachineEnumCanonicalizer.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/MachineEnumCanonicalizer.java @@ -180,10 +180,14 @@ public final class MachineEnumCanonicalizer { String canonical = canonicalizeLabel( event.fullIdentifier() != null ? event.fullIdentifier() : event.rawName(), enumTypeFqn); - if (canonical.equals(event.fullIdentifier())) { + String fnRaw = toFnForm(canonical, enumTypeFqn); + if (fnRaw == null) { + fnRaw = event.rawName(); + } + if (canonical.equals(event.fullIdentifier()) && fnRaw.equals(event.rawName())) { return event; } - return Event.of(event.rawName(), canonical); + return Event.of(fnRaw, canonical); } static State canonicalizeState(State state, String enumTypeFqn) { @@ -200,6 +204,11 @@ public final class MachineEnumCanonicalizer { if (isStringOrPrimitiveType(enumTypeFqn) && canonical.startsWith(enumTypeFqn + ".")) { String constant = canonical.substring(enumTypeFqn.length() + 1); raw = "\"" + constant + "\""; + } else { + String fnRaw = toFnForm(canonical, enumTypeFqn); + if (fnRaw != null) { + raw = fnRaw; + } } return State.of(raw, canonical); } @@ -315,4 +324,25 @@ public final class MachineEnumCanonicalizer { private static String simpleName(String fqn) { return fqn.contains(".") ? fqn.substring(fqn.lastIndexOf('.') + 1) : fqn; } + + /** + * Derives {@code EnumFormat.fn} display form ({@code OrderEvent.PAY}) from a package-canonical identifier. + */ + static String toFnForm(String canonicalFqn, String enumTypeFqn) { + if (canonicalFqn == null || canonicalFqn.isBlank() || isStringOrPrimitiveType(enumTypeFqn)) { + return null; + } + if (canonicalFqn.startsWith("<") || canonicalFqn.startsWith("\"")) { + return null; + } + if (!canonicalFqn.contains(".")) { + return canonicalFqn; + } + int lastDot = canonicalFqn.lastIndexOf('.'); + int prevDot = canonicalFqn.lastIndexOf('.', lastDot - 1); + if (prevDot > 0) { + return canonicalFqn.substring(prevDot + 1); + } + return simpleName(enumTypeFqn) + "." + canonicalFqn.substring(lastDot + 1); + } } diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/MachineEnumCanonicalizerTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/MachineEnumCanonicalizerTest.java index 844b606..5211ab7 100644 --- a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/MachineEnumCanonicalizerTest.java +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/MachineEnumCanonicalizerTest.java @@ -51,10 +51,33 @@ class MachineEnumCanonicalizerTest { assertThat(transition.getEvent().fullIdentifier()) .isEqualTo("com.example.order.OrderEvent.PAY"); + assertThat(transition.getEvent().rawName()).isEqualTo("OrderEvent.PAY"); assertThat(transition.getSourceStates().get(0).fullIdentifier()) .isEqualTo("com.example.order.OrderState.NEW"); + assertThat(transition.getSourceStates().get(0).rawName()).isEqualTo("OrderState.NEW"); assertThat(transition.getTargetStates().get(0).fullIdentifier()) .isEqualTo("com.example.order.OrderState.PAID"); + assertThat(transition.getTargetStates().get(0).rawName()).isEqualTo("OrderState.PAID"); + } + + @Test + void shouldAlignBareRawNameToFnForm(@TempDir Path tempDir) throws IOException { + writeSampleConfig(tempDir); + + CodebaseContext context = new CodebaseContext(); + context.scan(tempDir); + + StateMachineTypeResolver.MachineTypes types = StateMachineTypeResolver.resolveTypes( + "com.example.config.OrderStateMachineConfiguration", context); + + Transition transition = new Transition(); + transition.setEvent(Event.of("PAY", "PAY")); + transition.setSourceStates(List.of(State.of("NEW", "NEW"))); + + MachineEnumCanonicalizer.canonicalizeTransitions(List.of(transition), types); + + assertThat(transition.getEvent().rawName()).isEqualTo("OrderEvent.PAY"); + assertThat(transition.getSourceStates().get(0).rawName()).isEqualTo("OrderState.NEW"); } @Test