Architecture policies as executable evidence

Keep Java boundaries honest.

Import compiled classes without loading them, model their real dependency graph, evaluate deterministic rules, and publish reviewable results in tests and CI.

0target classes loaded
4stable CLI commands
10result and graph formats
2 OSlibrary and consumer CI

Five-minute quickstart

Analyze a normal Maven project.

Add the published release as a test dependency and point a bounded policy file at compiled classes.

Maven Central is the public registry; Central Portal is its publisher interface. Maven and Gradle consumers resolve version 0.1.0 from Central without needing a Portal account.

build.gradle.ktstest dependency
repositories {
    mavenCentral()
}

dependencies {
    testImplementation("io.github.tristankruse:archunitjava:0.1.0")
}
pom.xmltest dependency
<dependency>
  <groupId>io.github.tristankruse</groupId>
  <artifactId>archunitjava</artifactId>
  <version>0.1.0</version>
  <scope>test</scope>
</dependency>

A readable contract

Policy without executable configuration.

The CLI accepts exact or glob selectors from a strict, bounded properties schema. Unknown keys, escaping paths, duplicates, and executable factories are rejected.

  1. Compile the applicationArchUnitJava analyzes class directories and JARs as data.
  2. Select origin and target typesUse deterministic qualified-name patterns.
  3. Run the check in JUnit or CIPolicy failures and incomplete analysis remain distinct.
archunitjava.propertiesdependency boundary
schema=archunitjava.cli.v1
inputs=target/classes
rules=api-boundary
emptySelection=fail
allowIncompleteAnalysis=false

rule.api-boundary.domain=types
rule.api-boundary.mode=no
rule.api-boundary.origins=glob:com.example.api.**
rule.api-boundary.targets=glob:com.example.infrastructure.**
rule.api-boundary.external=ignore
rule.api-boundary.rationale=Keep adapters behind application ports

Use cases

Make architecture drift fail like any other test.

Dependency boundaries

Keep domain code independent, adapters behind ports, and APIs away from persistence details.

Cycles and coupling

Detect cycles across types, packages, slices, layers, and modules with concrete bytecode evidence.

CI evidence

Run policies in JUnit or the CLI and export stable JSON, SARIF, JUnit XML, and graph reports.

Capabilities

From bytecode evidence to architecture decisions.

The high-level CLI exposes a deliberately bounded dependency-rule subset. The public Java API also provides the lower-level importer, selectors, projections, rules, metrics, snapshots, baselines, and renderers.

Bytecode importer

Declarations, signatures, annotations, exceptions, calls, fields, constants, lambdas, method references, JARs, and JPMS metadata.

Architecture rules

Dependency, naming, location, inheritance, annotation, member access, cycles, layers, slices, modules, and presets.

Safe execution

Target classes and builds are never executed. Inputs, archives, caches, diagrams, and output paths have explicit boundaries.

JUnit integration

Ordinary assertions, dynamic cases, and an optional JUnit Platform engine with structured analysis failures.

Reports

Console, JSON, SARIF, JUnit XML, DOT, Mermaid, D2, CSV, graph JSON, and self-contained HTML.

Quality signals

Source, cohesion, and dependency metrics; reviewed baselines; graph snapshots; and reproducible performance measurements.

Independent evidence

A consumer repository, not a toy snippet.

The separate RAG fixture compiles a layered Java application and consumes ArchUnitJava only as a test-scoped Maven dependency. Its tests prove both acceptance and rejection paths.

Healthy boundaries

Domain code remains independent of infrastructure, and application services depend on domain ports rather than concrete adapters. Both policies must pass.

Deliberate violations

An unsafe controller reaches into infrastructure and a leaky adapter imports an API DTO. Both must fail with the concrete offending types retained as evidence.

Documentation

Read at the level you need.

ArchUnitEverything family

One product idea, native language workflows.

ArchUnitJava shares the goal and information structure of its Ruby, Python, and TypeScript siblings while using Java-native Maven, Gradle, JUnit, and Javadocs tooling.