javaarchunit

Can a single method be excluded from an ArchUnit class access rule?


I want to define an ArchUnit rule that prevents the use of the EntityManager class outside of my repository classes. I have one exception to this rule, a single call to entityManager.detach in com.myapp.EventService.

Currently my JUnit 5 rule looks like this:

    @ArchTest
    static final ArchRule onlyRepositoriesMayUseEntityManager = noClasses()
        .that().resideOutsideOfPackage("com.myapp.repository..")
        .and(are(not(equivalentTo(EventService.class))))
        .should().accessClassesThat().areAssignableTo(EntityManager.class);

But this will allow any method of EntityManager to be used in EventService. I would rather either of the following

  1. Allow only the detach method to be used in EventService
  2. Allow only the detach method to be used anywhere outside of the repositories

Solution

  • .should().accessTargetWhere( allows you to specify a DescribedPredicate for a JavaAccess (not to be confused with its AccessTarget 🤯 – cf. ArchUnit's domain model).

    With that, a solution for your option 1 could be (using DescribedPredicate.describe):

    @ArchTest
    ArchRule onlyRepositoriesMayUseEntityManager = noClasses()
        .that().resideOutsideOfPackage("com.myapp.repository..")
        .should().accessTargetWhere(describe("owner is assignable to EntityManager", access ->
            access.getTargetOwner().isAssignableTo(EntityManager.class) &&
            !(access.getOriginOwner().isEquivalentTo(EventService.class) &&
              access.getTarget().getName().equals("detach"))
        ));