Class GuardrailEngine

java.lang.Object
com.vaadin.swingbridge.migration.tool.guardrails.GuardrailEngine

public final class GuardrailEngine extends Object
The three migration guardrails, as rules over imported classes: no unvetted static state, no component in a static field, no JVM exit.

This is the implementation, not the migrator's entry point. A migrated app calls com.vaadin.swingbridge.migration.guardrails.MigrationGuardrails, a facade over this class in a test-scope artifact, so the migrator imports one SB-Emulators type and no com.tngtech.* (M1D_guardrails_artifact). The engine lives here because StaticSweep asks the same immutability question for the opposite purpose — a worklist during the migration rather than a gate after it — and answering it twice is what makes a rule drift (M1D_static_sweep_tool § Q_one_rule_engine). The shared half is ImmutableTypes.

The two terminals do not collapse into each other. violations() returns the report and judges nothing, which is what a `main` printing a worklist needs — mid-sweep a non-empty list is the expected state, not a failure. The facade's run() throws on the same list, which is what makes the sweep stay done once a static field is added months later.

This class never depends on :emulators, :surrogates or anything Vaadin: the component types are matched by name, so a migrated app's UI-free service module can install the gate without a Vaadin dependency flipping its Step-0 classification, and there the names resolve to nothing and the rule trivially passes.

  • Constructor Details

    • GuardrailEngine

      public GuardrailEngine(String... rootPackages)
      Parameters:
      rootPackages - the app's own roots. Leaving one out makes the rules pass by not looking at it; naming one wider than you own sweeps somebody else's classes into your result.
  • Method Details

    • forImportedClasses

      public static GuardrailEngine forImportedClasses(com.tngtech.archunit.core.domain.JavaClasses classes)
      Runs the rules over classes the caller imported, bypassing the package scan — and with it DO_NOT_INCLUDE_TESTS, which would skip a fixture living in test output.
    • allowSystemExitInMainMethods

      public GuardrailEngine allowSystemExitInMainMethods()
      Permits System.exit in the body of a public static void main(String[]) and nowhere else. A lambda inside main is not covered — deliberately, since invokeLater(() -> … System.exit(0)) is exactly the UI-reachable exit the gate exists to catch.
    • allowSystemExitIn

      public GuardrailEngine allowSystemExitIn(String... fullyQualifiedClassNames)
      Permits JVM exit anywhere in the named classes.
      Parameters:
      fullyQualifiedClassNames - matched exactly — "com.myapp.Main" does not cover com.myapp.Main$1, so an anonymous class stays gated
    • violations

      public List<String> violations()
      Every violation of all three rules, each entry a rendered failure report.

      Never short-circuits: stopping at the first would serialise the worklist into fix-statics, re-run, now discover the System.exit.

      Returns:
      empty when the app passes. **Judges nothing** — a caller printing a worklist wants the list, a caller gating a build throws on it.
      Throws:
      AssertionError - only if the roots resolved no classes at all, which is a mistyped root rather than a finding
    • checkStaticState

      public void checkStaticState()
      Throws:
      AssertionError - if a static field is neither provably immutable nor allowlisted
    • checkStaticComponents

      public void checkStaticComponents()
      Throws:
      AssertionError - if a static field's type is a component
    • checkJvmExit

      public void checkJvmExit()
      Throws:
      AssertionError - if any code unit terminates the JVM outside the permitted places