Page 156 - 《软件学报》2025年第7期
P. 156
孙伟杰 等: Java 依赖异味的实证研究与统一检测技术 3077
注于 Maven 和 Gradle 之间依赖树的冲突, 下面我们将详述各类危害的具体触发情境.
(a) 危害 6 依赖于 依赖于 依赖范围 implementation 意味着 lib
在 client 构建时不会出现
下游模块构建错误
Downstream 模块 client 模块 mod 依赖库 lib: implementation
包含类 包含类 包含类
client.C mod.B lib.A
import mod.B import lib1.A public class A { 但由于 lib1 中的类 A 是 C 的
public class C extends B { public class B extends A { ...
... ... } 父类, lib1 在 mod 构建时必须出现
} }
(b) 危害 7 依赖于 依赖于 预期依赖范围是 implementation, 意味
着事实上 lib 不应该在 client 构建时出现
下游模块构建成本增加
下游模块 client 模块 mod 依赖库 lib: api
构建时依赖库 在构建 client 时, 由于 lib 的实际依赖范围是 api,
包括 包括 虽然 lib 事实上不被需要,还是要被下载,导致构建成本增加
依赖库 lib1
模块 mod
(c) 危害 8 预期依赖范围 compile, 意味着
依赖于 依赖于 事实上 lib 在运行时应该出现 下游模块运行时错误
但实际依赖范围 test 意味着
下游模块 client 模块 mod 依赖库 lib: test
包含 包含类 包含类 实际上 lib 在运行时不会出现
import mod.RunA mod.RunA
lib.A
public class RunA {
RunA runner=new RunA (); public void runMtdLib (){ public class A {
Class.forName (“lib.A”); ...
runner.runMtdLib ();
} }
}
(d) 危害 9
依赖于 依赖于 预期依赖范围是 test, 意味 下游模块构建产物冗余
着事实上 lib 并不需要被打
下游模块 client 模块 mod 依赖库 lib:compile 包进构建产物中
在被打包成可执行构件时
可执行构件 由于 lib 的实际依赖范围是 compile,
包括 下游模块通过 mod 引入了 lib, 构建产物出现冗余
包括 包括
模块 client 模块 mod 依赖库 lib1
图 A9 异味 1.6 对下游模块的危害与对应触发场景
(a) 危害 1 依赖范围 test 会覆盖 compile,
导致 lib2 在 mod 构建时不会出现 构建错误
依赖于 依赖库 lib2: test
依赖于 依赖于 依赖范围 compile 意味着 lib2
在 mod 构建时应该出现
模块 mod 依赖库 lib1 依赖库 lib2: compile
包含类 包含类 包含类
mod.C lib1.B lib2.A
import lib1.B import lib2.A public class A {
public class C extends B { public class B extends A { ...
... ... }
} }
(b) 危害 3
依赖于 依赖于 依赖范围 runtime 意味着 lib2
在 mod 运行时应该出现 运行时错误
模块 mod 依赖库 lib1 依赖库 lib2: runtime
依赖范围 test 会覆盖 compile,
依赖库 lib2: test 导致 lib2 在 mod 运行时不会出现
图 A10 异味 1.7 可能危害与对应触发场景
(1) 构建错误: 其触发场景为模块源码中调用了某冲突依赖库中独有的特性. 以图 A11(a) 为例, 模块 mod 同时
维护了 Maven 和 Gradle 对应的配置文件, 但依赖库 lib 在 Maven 配置文件中的版本声明为 2.0.0, 而在 Gradle 配

