All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jexxa.jexxatest.architecture.AggregateRules Maven / Gradle / Ivy

package io.jexxa.jexxatest.architecture;

import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.importer.ImportOption;
import io.jexxa.addend.applicationcore.Aggregate;
import io.jexxa.addend.applicationcore.Repository;

import java.util.List;

import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAnyPackage;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.fields;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noFields;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noMethods;
import static io.jexxa.jexxatest.architecture.PackageName.APPLICATIONSERVICE;
import static io.jexxa.jexxatest.architecture.PackageName.DOMAIN;
import static io.jexxa.jexxatest.architecture.PackageName.DOMAIN_SERVICE;

public class AggregateRules extends ProjectContent {

    @SuppressWarnings("unused")
    AggregateRules(Class project)
    {
        this(project, ImportOption.Predefined.DO_NOT_INCLUDE_TESTS);
    }

    protected AggregateRules(Class project, ImportOption importOption)
    {
       super(project,importOption);
    }


    public void validate()
    {
        validateOnlyAggregatesHaveAggregatesAsFields();
        validateOnlyAggregatesAndNestedClassesAreMutable();
        validateOnlyRepositoriesAcceptAggregates();
        validateReturnAggregates();
    }

    protected void validateReturnAggregates()
    {
        var invalidReturnType = noMethods().that()
                .arePublic().and()
                .areDeclaredInClassesThat(resideInAnyPackage(APPLICATIONSERVICE, DOMAIN_SERVICE, DOMAIN))
                .and().areDeclaredInClassesThat().areNotAnnotatedWith(Aggregate.class)
                .and().areDeclaredInClassesThat().areNotAnnotatedWith(Repository.class)
                .should().haveRawReturnType(thatIsAnnotatedWithAggregate())
                .allowEmptyShould(true)
                .because("Aggregates contain the business logic and can only be returned by an aggregate or a repository!");

        invalidReturnType.check(importedClasses());
    }

    protected void validateOnlyRepositoriesAcceptAggregates() {
        var invalidReturnType = noMethods().that()
                .arePublic().and()
                .areDeclaredInClassesThat(resideInAnyPackage(APPLICATIONSERVICE, DOMAIN, DOMAIN_SERVICE))
                .and().areDeclaredInClassesThat().areNotAnnotatedWith(Repository.class)
                .should().haveRawParameterTypes(thatAreAggregates())
                .allowEmptyShould(true)
                .because("Aggregates contain the business logic and can only be accepted by a Repository!");

        invalidReturnType.check(importedClasses());
    }



    protected void validateOnlyAggregatesAndNestedClassesAreMutable() {
        var finalFields = fields().that().areDeclaredInClassesThat()
                .areNotAnnotatedWith(Aggregate.class).and()
                .areDeclaredInClassesThat().areNotNestedClasses()
                .should().beFinal()
                .allowEmptyShould(true)
                .because("Only Aggregates or nested classes are allowed to use non-final fields!");

        finalFields.check(importedClasses());
    }


    protected void validateOnlyAggregatesHaveAggregatesAsFields() {
        var invalidReturnType = noFields().that().areDeclaredInClassesThat()
                .resideInAnyPackage(APPLICATIONSERVICE, DOMAIN_SERVICE, DOMAIN)
                .and().areDeclaredInClassesThat().areNotAnnotatedWith(Aggregate.class)
                .should().haveRawType(thatIsAnnotatedWithAggregate())
                .allowEmptyShould(true)
                .because("Only aggregates can keep a reference to an aggregate!");

        invalidReturnType.check(importedClasses());
    }

    private static DescribedPredicate> thatAreAggregates() {
        return new DescribedPredicate<>("one parameter of type is an Aggregate") {
            @Override
            public boolean test(List javaClasses) {
                return javaClasses.stream().anyMatch(element -> element.isAnnotatedWith(Aggregate.class));
            }
        };
    }

    private static DescribedPredicate thatIsAnnotatedWithAggregate() {
        return new DescribedPredicate<>("one parameter of type is an Aggregate") {
            @Override
            public boolean test(JavaClass javaClass) {
                return javaClass.isAnnotatedWith(Aggregate.class);
            }
        };
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy