Skip to content

ArchUnit – is there a way to check package access with a generic placeholder?

I would like to check whether FOO.model is only accessed by FOO.service and BAR.model is only accessed by BAR.service and so on.

Is there a way to achieve this with ArchUnit? Like (pseudocode)

classes()
  .that().resideInAPackage("{PLACEHOLDER}.model")
  .should().onlyBeAccessed().byAnyPackage("{PLACEHOLDER}.service");

I’m aware I could write a test that iterates over all FOO, BAR etc packages, or write a separate test for every package, but I’m looking for a generic out-of-the-box solution where I do not have to update my test class every time I introduce a new package.

Answer

You can use a custom condition to test the origin of each access:

classes()
  .that().resideInAPackage("..model")
  .should(new ArchCondition<JavaClass>("only be accessed from the corresponding service package") {
    @Override
    public void check(JavaClass javaClass, ConditionEvents conditionEvents) {
      javaClass.getAccessesToSelf().forEach(access -> {
        String originPackageName = access.getOrigin().getOwner().getPackageName();
        String targetPackageName = access.getTarget().getOwner().getPackageName();
        String expectedOriginPackageName = targetPackageName.replace(".model", ".service");
        boolean satisfied = originPackageName.equals(expectedOriginPackageName);
        conditionEvents.add(new SimpleConditionEvent(access, satisfied, access.getDescription()));
      });
    }
  });

(There are probably more sophisticated ways to construct expectedOriginPackageName…)