d333ab3d39
- Convert Event and Rsvp from mutable POJOs to Java records - Move all 8 exception classes to application.service.exception sub-package - Add ArchUnit rule enforcing domain models must be records Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
93 lines
3.6 KiB
Java
93 lines
3.6 KiB
Java
package de.fete;
|
|
|
|
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
|
|
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
|
|
import static com.tngtech.archunit.library.Architectures.onionArchitecture;
|
|
|
|
import com.tngtech.archunit.core.domain.JavaClass;
|
|
import com.tngtech.archunit.core.importer.ImportOption;
|
|
import com.tngtech.archunit.junit.AnalyzeClasses;
|
|
import com.tngtech.archunit.junit.ArchTest;
|
|
import com.tngtech.archunit.lang.ArchCondition;
|
|
import com.tngtech.archunit.lang.ArchRule;
|
|
import com.tngtech.archunit.lang.ConditionEvents;
|
|
import com.tngtech.archunit.lang.SimpleConditionEvent;
|
|
|
|
@AnalyzeClasses(packages = "de.fete", importOptions = ImportOption.DoNotIncludeTests.class)
|
|
class HexagonalArchitectureTest {
|
|
|
|
@ArchTest
|
|
static final ArchRule onionArchitectureIsRespected = onionArchitecture()
|
|
.domainModels("de.fete.domain.model..")
|
|
.domainServices("de.fete.domain.port.in..", "de.fete.domain.port.out..")
|
|
.applicationServices("de.fete.application.service..")
|
|
.adapter("web", "de.fete.adapter.in.web..")
|
|
.adapter("persistence", "de.fete.adapter.out.persistence..")
|
|
.adapter("config", "de.fete.config..");
|
|
|
|
@ArchTest
|
|
static final ArchRule domainMustNotDependOnAdapters = noClasses()
|
|
.that().resideInAPackage("de.fete.domain..")
|
|
.should().dependOnClassesThat().resideInAPackage("de.fete.adapter..");
|
|
|
|
@ArchTest
|
|
static final ArchRule domainMustNotDependOnApplication = noClasses()
|
|
.that().resideInAPackage("de.fete.domain..")
|
|
.should().dependOnClassesThat().resideInAPackage("de.fete.application..");
|
|
|
|
@ArchTest
|
|
static final ArchRule domainMustNotDependOnConfig = noClasses()
|
|
.that().resideInAPackage("de.fete.domain..")
|
|
.should().dependOnClassesThat().resideInAPackage("de.fete.config..");
|
|
|
|
@ArchTest
|
|
static final ArchRule inboundPortsMustBeInterfaces = classes()
|
|
.that().resideInAPackage("de.fete.domain.port.in..")
|
|
.should().beInterfaces();
|
|
|
|
@ArchTest
|
|
static final ArchRule outboundPortsMustBeInterfaces = classes()
|
|
.that().resideInAPackage("de.fete.domain.port.out..")
|
|
.should().beInterfaces();
|
|
|
|
@ArchTest
|
|
static final ArchRule domainMustNotUseSpring = noClasses()
|
|
.that().resideInAPackage("de.fete.domain..")
|
|
.should().dependOnClassesThat().resideInAPackage("org.springframework..");
|
|
|
|
@ArchTest
|
|
static final ArchRule webMustNotDependOnPersistence = noClasses()
|
|
.that().resideInAPackage("de.fete.adapter.in.web..")
|
|
.should().dependOnClassesThat().resideInAPackage("de.fete.adapter.out.persistence..");
|
|
|
|
@ArchTest
|
|
static final ArchRule persistenceMustNotDependOnWeb = noClasses()
|
|
.that().resideInAPackage("de.fete.adapter.out.persistence..")
|
|
.should().dependOnClassesThat().resideInAPackage("de.fete.adapter.in.web..");
|
|
|
|
@ArchTest
|
|
static final ArchRule webAdapterMustNotDependOnOutboundPorts = noClasses()
|
|
.that().resideInAPackage("de.fete.adapter.in.web..")
|
|
.should().dependOnClassesThat().resideInAPackage("de.fete.domain.port.out..");
|
|
|
|
@ArchTest
|
|
static final ArchRule domainModelsMustBeRecords = classes()
|
|
.that().resideInAPackage("de.fete.domain.model..")
|
|
.and().doNotHaveSimpleName("package-info")
|
|
.should(beRecords());
|
|
|
|
private static ArchCondition<JavaClass> beRecords() {
|
|
return new ArchCondition<>("be records") {
|
|
@Override
|
|
public void check(JavaClass javaClass,
|
|
ConditionEvents events) {
|
|
boolean isRecord = javaClass.reflect().isRecord();
|
|
if (!isRecord) {
|
|
events.add(SimpleConditionEvent.violated(javaClass,
|
|
javaClass.getFullName() + " is not a record"));
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|