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

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


                 的冲突, 而不是模块与依赖库之间的冲突, 因此不会出现因为冲突类在模块中而被忽略的情况. 在这种情况下,
                 Maven  和  Gradle 项目都倾向于选择依赖树前序遍历序列中靠前的依赖库中的类.


                              (a) 类型 1.1    依赖于
                                       模块 mod     依赖库 lib
                                          包含类       包含类
                                         mod.Dup    mod.Dup
                                      public class Dup{  public class Dup{
                                         …          …                      模块和依赖库之间包含冲突类
                                      }          } 冲突
                                        依赖于      依赖于
                                    模块 mod   依赖库 lib1  依赖库lib2
                                              包含类        包含类
                                          lib.Dup      lib.Dup
                                        public class Dup{  public class Dup{
                                          …         冲突  …                      依赖库之间包含冲突类
                              (b) 类型 1.2  }         }
                                     依赖于       依赖于
                                           依赖库 lib1  依赖库 lib3: v1.0.0
                                     依赖于
                                 模块 mod
                                               依赖于
                                                        冲突
                                                                        依赖树中有冲突版本的同一依赖库
                              (c) 类型 1.3   依赖库 lib2  依赖库 lib3: v2.0.0
                              (d) 类型 1.4
                                 import lib2.A  mod 直接使用传递依赖 lib2
                                 A classA = new A();  中的类但未在配置文件中声明
                                  包含代码
                                                               lib2.A
                                    依赖于       依赖于       包含类  public class A {
                                                               ...              依赖库使用但未声明
                                                            }
                                模块 mod  依赖库 lib1:4.0.0  依赖库 lib2
                              (e) 类型 1.5
                                        依赖于
                                  模块 mod     依赖库 lib1
                                       mod 声明 lib1 为依赖库, 但并未使用其中的类              依赖库声明但未使用
                                                       <dependency>
                                      依赖于         相关配置   <groupId>example</groupId>
                                                          <artifactId>lib</artifactId>
                                                         <version>1.0.0</version>
                                 模块 mod      依赖库 lib   </dependency>  未声明依赖范围, 默认为 compile
                                            预期依赖范围: test     实际依赖范围: compile        实际范围与预
                              (f) 类型 1.6                   冲突                       期范围冲突
                                      依赖于          依赖于
                                 模块 mod  依赖于  依赖库 lib1  依赖库 lib2:compile
                                                                         依赖树中依赖库有冲突的依赖范围
                                                          冲突
                              (g) 类型 1.7     依赖库 lib2: test
                              (h) 类型 1.8
                                                           <dependency>
                                      依赖于          Maven 相关配置  <groupId>example</groupId>
                                                              <artifactId>lib</artifactId>
                                                             <version>1.0.0</version>
                                 模块 mod       依赖库 lib  Gradle 相关配置 </dependency>
                                                                                依赖库在 Maven 和
                                                                   冲突
                                      同时使用 Maven 和 Gradle                       Gradle 中版本不一致
                                                          implementation “example:lib: 2.0.0”
                                               图 A1 模块粒度依赖异味特征实例

                    3) 类别  1.3 库版本冲突: 模块的依赖树中存在同一依赖库的不同版本                 (7/47). 模块的依赖树中存在组织名和构
                 件名都相同但版本不同的依赖库. 在图            A1(c) 对应的#SELENIDE-1652 [42] 中, 模块的直接依赖   browsermob-core 和
                 selenide 都引入了  netty-all 作为传递依赖, 但  netty-all 的版本不同, 最终只有一个版本的     netty-all 被选择, 其余会被
                 忽略, 最终导致    NoSuchMethodError. 最终开发者移除了直接依赖       browsermob-core 解决了版本冲突.
                    这类异味在     Maven  和  Gradle 中皆存在, 产生原因主要在于依赖管理工具的版本调停机制. 当依赖树中存在同
                 一依赖库的不同版本时, 最终只有一个版本的依赖库会被选择. 然而, 在                    Maven  和  Gradle 下, 这类异味有不同的表
   142   143   144   145   146   147   148   149   150   151   152