Class NoBlanketCatchArchTest
NoBlanketCatch.
WARN mode (current sweep default). The L0-T0 #7 sweep introduces the
rule in warn mode — services have ~115 pre-existing blanket catches that are
being typed incrementally, so the rule must surface violations without
breaking the build. A consuming service writes (using the preferred single-scan
evaluate(JavaClasses) — see that method for the canonical ratchet form):
@Test
void noBlanketCatchWarn() {
JavaClasses classes = new ClassFileImporter()
.withImportOption(new ImportOption.DoNotIncludeTests())
.importPackages("com.aim2be.user");
var result = NoBlanketCatchArchTest.evaluate(classes);
if (!result.report().isEmpty()) {
LoggerFactory.getLogger(getClass()).warn("NoBlanketCatch (WARN):\n{}", result.report());
}
// intentionally no assertion in pure-warn; add a ratchet on result.count() to block new debt
}
BLOCK mode (post-W2 flip). Once a service's blanket catches are typed, replace the warn test with a hard gate:
@AnalyzeClasses(packagesOf = UserServiceApplication.class,
importOptions = ImportOption.DoNotIncludeTests.class)
class NoBlanketCatchGateTest { // distinct name — must NOT collide with this helper
@ArchTest
static final ArchRule rule = NoBlanketCatch.noBlanketCatchOutsideBoundary();
}
Name the BLOCK-mode class distinctly (e.g. NoBlanketCatchGateTest),
NOT NoBlanketCatchArchTest: a consumer class sharing this helper's
simple name in the same package would shadow the import and break any
evaluateForWarning(JavaClasses) callsite still present during the
WARN→BLOCK transition.
On the *ArchTest name. Despite the suffix this is a
consumer-facing helper/template, not a JUnit test class — it declares no
@Test / @ArchTest member and is never auto-discovered (it
lives in src/main, off the test classpath of this module). The name
deliberately mirrors its sibling EntityVersionParityArchTest so the
two shared-rule entry points read consistently (rule 10); the BLOCK-mode
snippet above shows the actual @ArchTest wiring a consumer writes.
The rule's own positive/negative self-test is NoBlanketCatchSelfTest
in src/test.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final recordImmutable carrier for a single rule evaluation — both the violationcount(for a ratchet assertion) and the formattedreport(for warn-mode logging), produced by one scan. -
Method Summary
Modifier and TypeMethodDescriptionevaluate(com.tngtech.archunit.core.domain.JavaClasses classes) EvaluatesNoBlanketCatch.noBlanketCatchOutsideBoundary()ONCE and returns both the violationcountand the formattedreportin a singleNoBlanketCatchArchTest.WarnResult.static StringevaluateForWarning(com.tngtech.archunit.core.domain.JavaClasses classes) EvaluatesNoBlanketCatch.noBlanketCatchOutsideBoundary()against the given classes and returns the formatted failure report, or an empty string when there are no violations.static intviolationCount(com.tngtech.archunit.core.domain.JavaClasses classes) Counts the blanket-catch violations in the given classes — the stable, non-string-parsed count consumers need for a ratchet assertion: pin the W1 baseline and assertviolationCount(...) <=that baseline so existing debt is tolerated while NEW blanket catches fail the build.
-
Method Details
-
evaluate
public static NoBlanketCatchArchTest.WarnResult evaluate(com.tngtech.archunit.core.domain.JavaClasses classes) EvaluatesNoBlanketCatch.noBlanketCatchOutsideBoundary()ONCE and returns both the violationcountand the formattedreportin a singleNoBlanketCatchArchTest.WarnResult.Preferred single-scan entry point. A warn-mode test typically needs both the count (for a ratchet assertion) and the report (to log). Calling
evaluateForWarning(JavaClasses)andviolationCount(JavaClasses)back-to-back evaluates the rule twice over the same classes; this method scans once and exposes both, e.g.:@Test void noBlanketCatchWarn() { JavaClasses classes = new ClassFileImporter() .withImportOption(new ImportOption.DoNotIncludeTests()) .importPackages("com.aim2be.user"); var result = NoBlanketCatchArchTest.evaluate(classes); if (!result.report().isEmpty()) { LoggerFactory.getLogger(getClass()).warn("NoBlanketCatch (WARN):\n{}", result.report()); } assertThat(result.count()).isLessThanOrEqualTo(W1_BASELINE); // ratchet }The
countis the size of the ArchUnitFailureReportdetail list (one entry per flagged catch clause) — identical semantics toviolationCount(JavaClasses); thereportis identical toevaluateForWarning(JavaClasses). Those two methods are retained for back-compat; new callers should prefer this single-scan method.- Parameters:
classes- the imported classes to evaluate (production package, tests excluded)- Returns:
- a
NoBlanketCatchArchTest.WarnResultcarrying the violation count and the report (count0+ report""when compliant)
-
evaluateForWarning
EvaluatesNoBlanketCatch.noBlanketCatchOutsideBoundary()against the given classes and returns the formatted failure report, or an empty string when there are no violations. The caller logs the report (warn mode) — no logging dependency is imposed on this module.- Parameters:
classes- the imported classes to evaluate (typically the service's production package, tests excluded)- Returns:
- the failure-report text, or
""when compliant
-
violationCount
public static int violationCount(com.tngtech.archunit.core.domain.JavaClasses classes) Counts the blanket-catch violations in the given classes — the stable, non-string-parsed count consumers need for a ratchet assertion: pin the W1 baseline and assertviolationCount(...) <=that baseline so existing debt is tolerated while NEW blanket catches fail the build. The count is the size of the ArchUnitFailureReportdetail list (one entry per flagged catch clause), not a line count of the rendered report — so it never drifts with the report's header/formatting.- Parameters:
classes- the imported classes to evaluate (production package, tests excluded)- Returns:
- the number of blanket-catch violations,
0when compliant
-