Page 127 - 《软件学报》2025年第7期
P. 127

3048                                                       软件学报  2025  年第  36  卷第  7  期


                 Maven  中的依赖范围误用表现形式较为单一. 在           9  个  Maven  依赖范围误用的问题报告中, 有      8  例中依赖库的预期
                 依赖范围为    test, 而实际依赖范围为    compile.
                    (7) 类别  1.7 依赖范围冲突: 直接依赖在依赖树中存在冲突的依赖范围                 (2/47). 依赖库同时作为模块的直接依
                 赖和间接依赖存在, 但直接依赖对应的依赖范围与间接依赖对应的依赖范围不一致. 在图                            3(b) 对应的#DW-3769 [33]
                 中, 模块导入   dropwizard:dropwizard-dependencies 中引入的依赖库  jakarta:jakarta.xml.bind-api:2.32 和  jakarta:jakarta.
                 xml.bind-api:2.32  为  test 范围的直接依赖. 然而, 这两个依赖库在传递依赖中同样存在, 并且它们的依赖范围被设
                 置为  compile. 这造成了依赖范围的冲突, 导致直接依赖中的测试范围覆盖了传递依赖中的                       compile 范围. 因此, 尽
                 管这两个依赖库预期在构建、运行和测试阶段都被使用, 但最终只在测试阶段中被引入使用. 最终开发者将直接
                 依赖的范围同样设置为        compile 以解决冲突.
                    这类异味仅存在于       Maven  中, 其产生原因在于     Maven  的内部结构中隐藏的一个深层漏洞#MNG-8041            [34] . 相
                 比之下, Gradle 并不受此类漏洞的影响, 因此不会产生类似的异味. 这个                Maven  中的缺陷广泛存在于其所有的          3.x
                 版本中, 其结果是导致项目在处理依赖库冲突时无法正常运作. 值得注意的是, 这类异味很容易被忽略, 因为在将
                 出现此异味的项目作为库使用时, 依赖范围冲突并不会立即显现出问题; 只有当模块自身作为应用程序被使用时,
                 才会出现相应危害.
                    (8) 类别  1.8 依赖树冲突: Maven  和  Gradle 解析出的依赖树不一致     (1/47). 模块同时包含   Maven  和  Gradle 的配
                 置文件, 且   Maven  和  Gradle 根据各自配置文件解析出的依赖树不一致. 在图             3(c) 对应的#MSJC-192  [35] 中, 模块
                 Msgraph-sdk-java-core 同时使用  Maven  和  Gradle 进行依赖管理, 然而在这两个构建工具对应的配置文件中, 对依
                 赖库  com.azure:azure-identity  和  com.google.guava:guava 的版本声明却不一致. 最终开发者将  Maven  配置文件中
                 的版本配置调整为与       Gradle 一致, 并且引入自动化机器人以确保          Maven  中依赖版本保持与     Gradle 中一致.
                    这类异味仅存在于同时使用           Maven  和  Gradle 作为构建工具的项目中, 其产生原因主要在于开发者对项目配
                 置文件的修改未能同步至所有相关的构建工具对应的配置文件中. 以模块                         Msgraph-sdk-java-core 为例, 其选择使
                 用  Gradle 进行依赖管理, 但也同时维护了        Maven  的配置文件, 以确保项目能够兼容不同的环境. 在             MSJC-176  [36]
                 中, 项目中对依赖库      guava 进行升级, 但仅在    Gradle 对应的配置文件    build.gradle 中进行了修改, 而并未将修改同
                 步至  Maven  对应的  pom.xml, 造成了  Maven  和  Gradle 依赖树的冲突. 最终在  MSJC-192 [35] 中, 开发者发现并修复
                 了此问题.
                    2) 项目粒度
                    在项目级别, 我们发现了        11  个 (占比  11/47=23.4%) 问题报告中的  5  种 (占比  5/13=38.5%) 依赖异味类别, 它
                 们分别对应表     3  中的类别  2.1–2.5. 为了完整地进行分类, 我们基于        Maven  和  Gradle 为项目管理提供的手段进行
                 考虑, 并关注其中涉及的依赖管理的具体实体               (如构建工具封装器). 最终我们总结出           5  类异味, 它们涵盖了    11  个
                 问题报告, 并且都同时存在于         Maven  和  Gradle 中. 接下来, 我们将给出异味   2.1–2.5  的定义. 由于篇幅限制, 我们将
                 对其中异味类别      2.2  和  2.3  进行详细介绍  (其他异味类别的详细分析也参见附录           A), 它们都是先前研究未涉及或
                 未充分讨论的, 并且分别对应了不同的构建工具.
                    (1) 类别  2.1 构建工具配置缺失: 项目中缺少对其所使用构建工具的配置                  (2/47). 项目中缺少所使用的构建工
                 具的版本等关键信息的配置文件.
                    (2) 类别  2.2 构建工具封装器    JAR  缺失: 项目构建工具封装器对应的         JAR  包缺失  (6/47). 项目中所使用的构建
                 工具封装器所需的       JAR  包未出现在封装器对应路径下. 在图          3(d) 对应的#PENNA-16  [37] 中, 项目  Penna 在上传至
                 GitHub  时没有将  gradle-wrapper.jar 与项目的其他代码一起上传.gradle-wrapper.jar 是  Gradle 封装器的一部分, 它
                 用于自动下载和配置       Gradle 的特定版本, 以确保项目的构建与特定版本的              Gradle 兼容. 由于  gradle-wrapper.jar 的
                 缺失, 因此在尝试通过封装器脚本           gradlew  启动  Gradle 时, 脚本无法找到  gradle-wrapper.jar, 最终导致了  ClassNot
                 FoundException  异常. 开发者通过上传对应的     gradle-wrapper.jar 解决了此问题.
                    这类异味在     Maven  和  Gradle 中均存在, 其出现的主要原因是       JAR  包是二进制文件, 在版本控制系统的管理
                 中通常会忽略二进制文件, 因此构建工具封装器               JAR  更容易缺失. 以#LEGAL-570   [38] 为例, ASF  项目中允许源代码
   122   123   124   125   126   127   128   129   130   131   132