You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过ArchUnit规则检查叶子包中的文件(类、接口等)数量不超过N个

如何通过ArchUnit规则检查叶子包中的文件(类、接口等)数量不超过N个

这个需求确实很实用,ArchUnit本身没有直接提供统计包内文件数的API,但我们可以通过自定义条件来实现这个规则,下面一步步来完成:

第一步:明确核心逻辑

我们需要两个关键判断:

  • 识别叶子包:也就是没有子包的底层包(如果一个包下还有子包,就跳过,只检查最底层的包)
  • 统计每个叶子包下被ArchUnit扫描到的类/接口/枚举等的数量,确保不超过设定的阈值(比如你例子里的8个)

第二步:实现自定义检查条件

我们可以编写一个自定义的ArchCondition来处理包的数量验证,同时在规则里过滤出叶子包:

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.domain.JavaPackage;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.lang.SimpleConditionEvent;
import org.junit.jupiter.api.Test;

import java.util.Set;
import java.util.stream.Collectors;

public class PackageSizeArchTest {

    private static final int MAX_CLASS_COUNT = 8;

    @Test
    void leafPackagesShouldNotExceedMaxClassCount() {
        // 导入你要扫描的类,这里替换成实际的扫描路径
        JavaClasses importedClasses = com.tngtech.archunit.core.importer.ClassFileImporter()
                .importPackages("natural");

        // 获取所有包
        Set<JavaPackage> allPackages = importedClasses.getPackages();

        // 过滤出叶子包:没有子包的包
        Set<JavaPackage> leafPackages = allPackages.stream()
                .filter(package_ -> isLeafPackage(package_, allPackages))
                .collect(Collectors.toSet());

        // 自定义条件:检查包内类数量不超过阈值
        ArchCondition<JavaPackage> notTooManyClasses = new ArchCondition<>("not contain more than " + MAX_CLASS_COUNT + " classes") {
            @Override
            public void check(JavaPackage javaPackage, ConditionEvents events) {
                long classCount = importedClasses.stream()
                        .filter(clazz -> clazz.getPackageName().equals(javaPackage.getName()))
                        .count();

                if (classCount > MAX_CLASS_COUNT) {
                    events.add(SimpleConditionEvent.violated(javaPackage,
                            String.format("Package %s contains %d classes, which exceeds the maximum of %d",
                                    javaPackage.getName(), classCount, MAX_CLASS_COUNT)));
                }
            }
        };

        // 对所有叶子包应用规则检查
        com.tngtech.archunit.lang.syntax.ArchRuleDefinition.packages()
                .that().areIn(leafPackages)
                .should(notTooManyClasses)
                .check(importedClasses);
    }

    // 判断一个包是否是叶子包:不存在以该包为父包的子包
    private boolean isLeafPackage(JavaPackage package_, Set<JavaPackage> allPackages) {
        String packageName = package_.getName();
        return allPackages.stream()
                .noneMatch(p -> p.getName().startsWith(packageName + "."));
    }
}

第三步:代码说明

  1. 叶子包判断:isLeafPackage方法通过检查所有包中是否存在以当前包为前缀的子包,来确定是否是叶子包
  2. 类数量统计:在自定义ArchCondition中,我们通过流过滤出属于当前包的类,统计数量后和阈值对比
  3. 规则应用:最后把过滤出的叶子包作为规则的目标,应用自定义条件进行检查

注意事项

  • 这里的“文件数”其实是ArchUnit扫描到的代码元素数(类、接口、枚举、注解等),如果你的包里有非代码文件(比如配置文件、资源文件),ArchUnit不会统计这些
  • 你可以根据实际需求调整MAX_CLASS_COUNT的值,以及扫描的包路径
  • 如果需要更灵活的范围(比如只检查特定前缀的包),可以在过滤叶子包的时候加上额外的条件

备注:内容来源于stack exchange,提问作者PatPanda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 09:59:36