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 配
   151   152   153   154   155   156   157   158   159   160   161