解决传递依赖之间的冲突



我有一个pom.xml,其中我有hadoop-core依赖

<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-core</artifactId>
<version>${hadoop.version}</version>
<scope>provided</scope>
</dependency>

当我添加cfg4j作为编译时依赖

<dependency>
<groupId>org.cfg4j</groupId>
<artifactId>cfg4j-core</artifactId>
<version>4.4.0</version>
</dependency>
<dependency> 
<groupId>org.cfg4j</groupId>
<artifactId>cfg4j-consul</artifactId>
<version>4.4.0</version>
</dependency>

我有一个异常"java.lang。NoSuchMethodError: javax.ws.rs.core.Response.someMethod"。我调查了这个问题,发现问题来自hadoop和cfg4j-consul。Hadoop核心依赖于jersey-core, cfg4j依赖于cxf。两者都将javax.ws.rs声明为依赖项,因此问题是jersey的版本是1.1,而cxf的版本是2.0.2。提供Hadoop依赖,因为Flink(框架)需要它,它在lib文件夹中。我不能只是升级它或删除它,也不能将它添加为编译时并排除lib。即使我能够做到这一点,我也不能保证hadoop会像预期的那样工作。我猜阴影不能解决问题,因为它不是与cfg4j,而是他的依赖关系之一。有解决冲突的方法吗?gradle有自己的方法来解决这样的问题吗?

两种方法:

  • Shading:正如你所说的,这有点困难,因为这是一个可传递的依赖项,但我想看看Maven的阴影插件,如果有必要,它仍然可以直接声明依赖项。
  • 不要使用依赖项,并尝试寻找其他库或解决方案来解决您的问题。

尝试以下步骤,这里是源代码:https://reflectoring.io/nosuchmethod/你的问题与maven和Gradle之间的选择无关,因此切换也无济于事。

修复NoSuchMethodErrorNoSuchMethodErrors有很多不同的风格,但它们都归结为一个事实,即编译时类路径不同于运行时类路径。

以下步骤将有助于查明问题:

步骤1:找出课程的来源首先,我们需要找出包含有问题的方法的类来自哪里。我们在NoSuchMethodError的错误信息中发现了这个信息:

Exception in thread "main" java.lang.NoSuchMethodError: 
io.reflectoring.nosuchmethod.Service.sayHello(Ljava/lang/String;)Ljava/lang/String;

现在,我们可以在web或IDE中搜索哪个JAR文件包含这个类。在上面的例子中,我们可以看到它是来自我们自己的代码库的Service类,而不是来自另一个库的类。

如果找不到该类的JAR文件,可以在运行应用程序时添加Java选项-verbose:class。这将导致Java打印出所有的类和它们加载的jar:

[Loaded io.reflectoring.nosuchmethod.Service from file:
/C:/daten/workspaces/code-examples2/patterns/build/libs/java-1.0.jar]

步骤2:找出谁调用了这个类接下来,我们要找出调用方法的位置。该信息在堆栈跟踪的第一个元素中可用:

Exception in thread "main" java.lang.NoSuchMethodError: 
io.reflectoring.nosuchmethod.Service.sayHello(Ljava/lang/String;)Ljava/lang/String;
at io.reflectoring.nosuchmethod.ProvokeNoSuchMethodError.main(ProvokeNoSuchMethodError.java:7)

这里,类ProvokeNoSuchMethodError试图调用一个在运行时不存在的方法。我们现在应该找出这个文件属于哪个库。

步骤3:检查版本既然我们知道了NoSuchMethodError在哪里被激发,缺少了什么方法,我们就可以采取行动了。

我们现在应该列出所有的项目依赖项。

在Gradle中,我们可以调用:

。/gradlew dependencies>dependencies.txt如果我们使用Maven,可以使用以下命令获得类似的结果:

mvn dependency:list>dependencies.txt"在这个文件中,我们可以搜索包含缺少方法的类和尝试调用该方法的类的库。

通常我们会在某处找到这样的输出:

--- org.springframework.retry:spring-retry:1.2.2.RELEASE
|     --- org.springframework:spring-core:4.3.13.RELEASE -> 5.0.8.RELEASE

上面的意思是spring-retry库依赖于4.3.13版本的spring-core,但是其他一些库也依赖于5.0.8版本的spring-core,并且推翻了依赖版本。

我们现在可以在dependencies.txt文件中搜索5.0.8。

最后,我们需要决定我们实际上需要哪一个版本来满足这两个依赖项。通常,这是较新的版本,因为大多数框架在某种程度上是向后兼容的。然而,也有可能是另一种方式,或者我们甚至根本无法解决冲突。

最新更新