ArchUnit 不直接支持 PECS 原则校验,但可通过自定义规则结合 JavaMethod、JavaParameter 和泛型类型解析能力,手动检查方法签名是否符合 PECS 惯例:识别返回值中 ? extends T(生产者)和参数中 ? super T(消费者),并针对原始类型、无界通配符等不安全用法报错,同时提供可操作改进建议。

ArchUnit 本身不直接支持 Java 泛型的 PECS(Producer Extends, Consumer Super)原则校验,它无法自动推断泛型参数在 API 中是作为生产者还是消费者。但你可以通过自定义规则,结合 ArchUnit 的 JavaMethod、JavaParameter、JavaType 和泛型类型解析能力,手动检查方法签名是否符合 PECS 惯例。
识别泛型参数的使用角色(生产者 vs 消费者)
PECS 的核心在于:若泛型类型用于返回值或只读场景(如 Collection<? extends T>),它是生产者;若用于入参且可能被写入(如 Collection<? super T>),它是消费者。ArchUnit 可通过以下方式判断:
- 检查方法返回类型中是否含
? extends X—— 应鼓励,否则提示“应使用 extends 声明协变返回” - 检查参数类型是否含
? super X—— 应鼓励,否则提示“输入集合应支持逆变,建议用 super” - 对通配符类型(
WildcardType)调用getExtendsBound()或getSuperBound()获取边界类型 - 注意原始类型(raw type)或无界通配符(
?)属于不安全用法,可列为违规项
编写 ArchUnit 规则检查泛型通配符合规性
以检查公共 API 方法中 Collection<T> 是否应改为带通配符的声明为例:
- 用
methods().that().arePublic().and().declaredInClassesThat().resideInAPackage("api..")定位目标方法 - 遍历每个
JavaMethod的参数和返回类型,调用getRawType()和getTypeArguments()提取泛型结构 - 对每个泛型参数类型,用
isWildcard()判断是否为通配符,并进一步检查其上下界 - 例如:发现参数类型为
Collection<String>且方法内部仅遍历该集合(未添加元素),则建议改为Collection<? extends String>
处理复杂泛型嵌套与类型变量约束
真实 API 常含多层泛型(如 Function<? super T, ? extends R>)或类型变量(<T extends Comparable<T>>)。ArchUnit 需谨慎解析:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 避免仅靠字符串匹配(如正则找 “extends”),而应使用
JavaType的 API 获取语义化边界 - 对类型变量(
TypeVariable),需结合其声明处的bounds判断是否隐含 PECS 意图(如<T extends Number>在返回值中合理,但在入参中若仅读取,仍宜用? extends Number) - 注意桥接方法(bridge methods)可能干扰判断,可用
isBridge()过滤 - 对
Optional<T>、Supplier<T>等典型生产者类型,可预设规则:返回 Optional 应倾向Optional<? extends T>(虽实际极少这么写,但可作教学检查)
集成到构建流程并给出可操作提示
规则不应只报错,而应提供明确改进建议:
- 在违规消息中注明“方法 [xxx] 参数 [yyy] 声明为 List<String>,但仅读取元素,建议改为 List<? extends String>”
- 将检查范围限定在
@Api或@PublicApi注解的类/方法上,避免过度检查内部工具类 - 配合 IDE 插件(如 ArchUnit IntelliJ Plugin)实现实时提示,提升采纳率
- 注意 JDK 版本差异:Java 12+ 对泛型反射 API 更稳定,旧版本中
getActualTypeArguments()可能返回 null,需做空判断
不复杂但容易忽略的是:PECS 是设计约定,不是语法强制。ArchUnit 规则的价值在于把团队共识编码成可执行检查,而不是替代开发者思考。关键在精准识别使用意图,而非机械匹配关键字。

















