Page 126 - 《软件学报》2025年第7期
P. 126
孙伟杰 等: Java 依赖异味的实证研究与统一检测技术 3047
Gradle 时都可能出现. 接下来, 我们将给出异味 1.1–1.8 的定义. 由于篇幅限制, 我们对最后的 3 类异味 (即 1.6–1.8)
将给出详细介绍 (包括例子分析; 而其他类别异味的详细介绍和例子分析参见附录 A), 它们都是先前研究未涉及
或未充分讨论的, 并且分别对应了不同的构建工具.
(1) 类别 1.1 内外类名冲突: 模块与依赖库中包含完全限定名相同的类 (2/47). 模块源代码中的类与模块所使
用的依赖库中的类完全限定名相同.
(2) 类别 1.2 外部类名冲突: 模块的依赖库之间包含完全限定名相同的类 (7/47). 模块所使用的依赖库之间包
含完全限定名相同的类.
(3) 类别 1.3 库版本冲突: 模块的依赖树中存在同一依赖库的不同版本 (7/47). 模块的依赖树中存在组织名和
构件名都相同但版本不同的依赖库.
(4) 类别 1.4 未声明依赖: 模块直接使用了未在配置文件中声明的依赖库 (6/47). 模块源代码中使用某依赖库
中的类, 但此依赖库并未在项目的配置文件中得到明确声明.
(5) 类别 1.5 未使用依赖: 模块在配置文件中声明的依赖库实际上并未被使用 (6/47). 模块源代码中并未使用
某依赖库中的任何类, 但此依赖库却在配置文件中声明.
(6) 类别 1.6 依赖范围误用: 依赖库的实际依赖范围与预期依赖范围不一致 (12/47). 依赖库在配置文件中的依
赖范围, 也即实际依赖范围, 与其在模块中的真实使用场景所对应的预期依赖范围不一致. 在图 3(a) 对应的
#CNNIP-4 [32] 中, 项目 Cavisson-ns-nd-integration-plugin 在声明依赖库 jenkins-ci:jenkins-test-harness:2.25 时未指定
其依赖范围, 导致 Maven 自动将其依赖范围设置为默认的 compile. 然而 jenkins-test-harness 事实上是一个与测试
相关的依赖库, 应该仅在测试阶段使用, 因此其预期范围应为 test, 导致实际依赖范围与预期不符. 这意味着依赖库
会在项目的构建、运行和测试阶段均被引入, 从而导致了依赖的冗余. 为了解决这个问题, 开发者最终将 jenkins-
test-harness 的依赖范围修改为预期的 test, 确保它仅在测试阶段被引入.
<dependency>
依赖于 具体配置 <groupId>example</groupId>
<artifactId>lib</artifactId>
<version>1.0.0</version>
模块 mod 依赖库 lib </dependency>
未声明依赖范围, 默认为 compile
冲突! 实际范围与预期范围冲突!
(a) 类型 1.6 预期范围: test 实际范围: compile
依赖于 依赖于
依赖库 lib1 依赖库 lib2: compile
模块 mod 依赖于
直接依赖与间接依赖范围冲突!
(b) 类型 1.7 依赖库 lib2: test 依赖范围冲突!
<dependency>
依赖于 Maven 中具体配置 <groupId>example</groupId>
<artifactId>lib</artifactId>
模块 mod <version>1.0.0</version>
依赖库 lib Gradle 中具体配置
</dependency>
模块同时使用
依赖版本冲突! 依赖库在 Maven 和 Gradle 中版本冲突!
(c) 类型 1.8 Maven 和 Gradle! implementation “example:lib1: 2.0.0”
通过脚本启动 Gradle 调用启动器 jar
gradle-wrapper.jar
项目 pr Gradle 启动器脚本 gradlew gradle-wrapper.jar 缺失!
(d) 类型 2.2
通过脚本启动 v5.6.4 版本 Gradle 调用启动器 jar
gradle-wrapper.jar
gradle-wrapper.jar 异常!
Gradle 启动器脚本 gradlew
项目 pr
校验和错误!
(e) 类型 2.3 v5.6.4 版本 jar 的预期校验和: 3dc39a 实际校验和: ad63ba
图 3 出现依赖异味特征的案例
这种异味在 Maven 和 Gradle 中都存在, 其产生原因主要在于开发者对依赖库具体使用场景的认知错误, 从而
无法选择正确的依赖范围. 虽然 Maven 和 Gradle 中都存在依赖范围的概念, 但由于它们对依赖范围的实现和定义
不同, 依赖范围误用在 Maven 和 Gradle 中表现出不同的形式. 由于 Maven 中仅有 6 个固定的依赖范围, 因此

