0

我想编写一个 ArchUnit 规则来验证服务类(由@ServiceSpring 注释注释)将仅使用其自己的包中的存储库,而不使用其他包中的存储库。

我目前有:

noClasses().that()
  .areAnnotatedWith(Service.class)
  .should()
  .dependOnClassesThat().areAnnotatedWith(Repository.class)
  .orShould().dependOnClassesThat().haveSimpleNameEndingWith("Repository")

这不好,因为它根本不允许对存储库有任何依赖。

或者,我可以这样做:

noClasses().that()
  .resideInAPackage("com.company.backend.user")
  .and()
  .areAnnotatedWith(Service.class)
  .should()
  .dependOnClassesThat(resideOutsideOfPackage("com.company.backend.user").and(annotatedWith(Repository.class)))
  .orShould().dependOnClassesThat(have(resideOutsideOfPackage("com.company.backend.user").and(simpleNameEndingWith("Repository"))))
  .as("Service classes should only use Repository class(es) from the own package");

但是我重复了包名com.company.backend.user3 次我需要为每个包定义这个规则。

4

1 回答 1

0

您需要在依赖项上定义一个谓词并对其进行操作。

classes()
    .that()
    .areAnnotatedWith(Service.class)
    .should(ArchConditions.onlyHaveDependenciesWhere(RepositoryAccessesAreOnlyWithinPackage.PREDICATE));

谓词检查访问目标是否是存储库,如果是,它将验证目标是否与调用类位于同一包中:

private static class RepositoryAccessesAreOnlyWithinPackage
        extends DescribedPredicate<Dependency> {

    public static final DescribedPredicate<Dependency> PREDICATE = new RepositoryAccessesAreOnlyWithinPackage();

    public RepositoryAccessesAreOnlyWithinPackage() {
        super("repository accesses are only within the same package");
    }

    @Override
    public boolean apply(Dependency dependency) {
        if (isRepositoryAccess(dependency)) {
            return areClassesInTheSamePackage(dependency.getOriginClass(), dependency.getTargetClass());
        }

        return true;
    }

    private boolean isRepositoryAccess(Dependency dependency) {
        return dependency.getTargetClass().isAnnotatedWith(Repository.class);
    }

    private boolean areClassesInTheSamePackage(JavaClass originClass, JavaClass targetClass) {
        return originClass.getPackageName().equals(targetClass.getPackageName());
    }
}
于 2020-11-17T07:37:36.963 回答