使用 ArchUnit 限制对静态方法的访问

Restricting access to static methds with ArchUnit

在我们的架构指南中,我们应该只在域模型或存储库实现(位于基础设施层)中实例化业务异常

我们通常使用工厂方法创建异常。

所以我想为此制定一个 ArchUnit 规则。应该遵循以下原则: 只有驻留在 domain 中的 classes 或者是 Repositories 的实现才能大声调用带有 @BusinessException

注释的 classes 的静态方法

我们所有的业务异常都带有@BusinessException 注释。所以很容易找到它们。

我尝试了它的变体:

 noClasses().that().resideOutsideOfPackages(DOMAIN).or(areImplementing(Repository.class))
                .should().callMethodWhere(
                target(owner(isAnnotatedWith(BusinessException.class)))
                        .and(target(modifier(JavaModifier.STATIC))));

areImplementing() 是一个自定义谓词,用于确定 class 是否是存储库的实现。

此代码无法编译。 isAnnotatedWith不能这样用

我也尝试了

的变体
methods().that().areStatic()
              .and().areDeclaredInClassesThat().areAnnotatedWith(BusinessException.class)
              .should().onlyBeCalled().byClassesThat(areImplementing(Repository.class))

同样,这不编译,onlyBeCalled不存在。

有人有想法吗?

我不完全确定是否有更短的形式来表达您想要的内容,但我相信以下使用自定义谓词的代码片段可以完成这项工作。

noClasses().that()
            // Restriction applies to all classes outside DOMAIN package that are not Repository classes
            .resideOutsideOfPackages(DOMAIN)
            .and()
            .areNotAssignableFrom(Repository.class)
            .should()
            .callMethodWhere(describe("static methods in BusinessExceptions",
                              // Target method may not reside in class annotated with BusinessException
                methodCall -> methodCall.getTarget().getOwner().isAnnotatedWith(BusinessException.class) 
                       // And target method may not have the static modifier
                    && methodCall.getTarget()
                        .resolve()
                        .stream()
                        .anyMatch(m -> m.getModifiers().contains(JavaModifier.STATIC))));

我唯一不确定的是 methodCall.getTarget().resolve() returns 一组 JavaMethod 类.