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

孙伟杰 等: Java 依赖异味的实证研究与统一检测技术                                                    3069


                 现形式, 因为它们有着不同的版本调停机制. 在出现版本冲突时, Maven                   会选择依赖树中离模块         (也就是树根) 最
                 近的依赖库; 而    Gradle 会选择较高版本的依赖库. 以#SCG-79      [91] 为例, 模块的依赖树中同时存在       google-auth-library-
                 credentials:0.4.0  和  google-auth-library-credentials:0.7.0. 此时, Maven  选择版本  0.4.0, 而  Gradle 选择版本  0.7.0. 由于
                 模块中实际使用的是        0.7.0  版本, 引用了  0.4.0  版本中不存在的类   ServiceAccountSigner, 因此依赖管理工具若为
                 Maven  则会出现  ClassNotFoundException, 若为  Gradle 则不会.
                    4) 类别  1.4 未声明依赖: 模块直接使用了未在配置文件中声明的依赖库                  (6/47). 模块源代码中使用某依赖库中
                                                                                     [5]
                 的类, 但此依赖库并未在项目的配置文件中得到明确声明. 在图                    A1(d) 对应的#EL-1849 中, 模块使用了依赖库
                 asm  但未在自身的配置文件中声明, 但直接依赖             moxy  引入了  asm  作为其传递依赖, 从而让模块能够正常访问
                 asm  中的类以进行构建和运行. 最终开发者将           asm  声明为直接依赖, 解决了依赖库未声明的情况.
                    这类异味在     Maven  和  Gradle 中皆存在, 产生原因在于未声明的依赖库同时作为传递依赖存在, 这使得在模块
                 构建或者运行时并不会直接报告缺少声明的依赖库. 这种情况下, 开发者会误以为依赖库已经被正确地声明了, 因
                 为模块能够正常工作.
                    5) 类别  1.5 未使用依赖: 模块在配置文件中声明的依赖库实际上并未被使用                   (6/47). 模块源代码中并未使用某
                 依赖库中的任何类, 但此依赖库却在配置文件中声明. 在图                  A1(e) 对应的#HFJS-581 [50] 中, 项目在构建文件中声明
                 了依赖库   javax-samples, 但实际上并未引用其中类. 最终开发者在配置文件中移除了依赖库                  javax-samples.
                    这类异味在     Maven  和  Gradle 中皆存在, 产生原因主要是     Maven  和  Gradle 只会在无法找到对应依赖库时报
                 错, 而不会在出现冗余依赖库时报错. 这意味着当模块中存在未被使用的依赖库时, 构建工具并不会发出警告或报
                 错信息. 因此, 开发者很容易忽视这些未使用的依赖库, 错误地认为它们是模块所需的一部分.

                 A1.2    项目粒度
                    1) 类别  2.1 构建工具配置缺失: 项目中缺少对其所使用构建工具的配置                  (2/47). 项目中缺少所使用的构建工具
                 的版本等关键信息的配置文件. 在图            A2(a) 对应的#PK-441  [92] 中, 项目中缺少了对  Maven  必要的文件如     maven-
                 wrapper.properties, 导致无法准确确定使用的 Maven 版本. 最终这种不一致性导致了开发环境与持续集成                    (CI) 中
                 Maven 版本的不匹配, 进而导致项目输出的不一致.

                                    开发过程中使用
                                                maven-wrapper.properties  Maven
                                    Maven v3.8.6                             maven-wrapper.properties
                                项目 pr                         运行时使用 Maven v3.9.0   缺失
                              (a) 类型 2.1
                                    调用封装器脚本         调用封装器 JAR
                                                               gradle-wrapper.jar
                                项目 pr       Gradle 封装器脚本 gradlew              gradle-wrapper.jar 缺失
                              (b) 类型 2.2
                                    调用封装器脚本以        调用封装器 JAR  gradle-wrapper.jar
                                    启动 Gradlev5.6.4                           gradle-wrapper.jar 异常
                                项目 pr       Gradle 封装器脚本 gradlew   冲突
                              (c) 类型 2.3    v5.6.4 版本的预期校验和: 3dc39a  文件的实际校验和: ad63ba
                                    包含       依赖于
                                                                            模块间依赖库未统一管理
                                项目 pr   模块 mod1  依赖库 lib: v1.0.0
                                    包含
                                             依赖于       未集中管理
                              (d) 类型 2.4  模块 mod2  依赖库 lib: v1.0.0
                                    包含      依赖于
                                                                             模块间依赖库版本冲突
                                项目 pr  模块 mod1  依赖库 lib: v1.0.0
                                    包含
                                            依赖于         冲突
                              (e) 类型 2.5  模块 mod2  依赖库 lib: v2.0.0
                                              图 A2 项目粒度依赖异味特征实例.
   143   144   145   146   147   148   149   150   151   152   153