使用decline解析Spark应用命令行参数时遇cats依赖错误
Spark加载Decline胖Jar时出现
java.lang.NoSuchMethodError: cats.kernel.Semigroup$.catsKernelMonoidForList()错误 问题场景
使用Decline库为Spark应用做命令行参数解析,通过sbt assembly构建胖Jar后,用spark-shell --jars加载该包并调用参数解析方法时,抛出如下错误:
java.lang.NoSuchMethodError: cats.kernel.Semigroup$.catsKernelMonoidForList()Lcats/kernel/Monoid; at com.monovore.decline.Help$.optionList(Help.scala:74) ...
但将该Jar添加到本地Scala环境类路径运行时,能正常返回预期的帮助信息;切换Scala 2.13+Spark 3.2.2组合,问题依然存在。
问题原因
这是依赖版本冲突导致的:
- Decline 2.3.0依赖的是Cats 2.x版本(包含
catsKernelMonoidForList方法) - Spark 3.1.2/3.2.2内置的是Cats 1.x旧版本(该方法不存在)
Spark启动时会优先加载自身内置的依赖类,导致运行时JVM找不到新版Cats才有的方法,抛出NoSuchMethodError。
解决方案
方案1:用sbt-assembly的Shade规则重命名Cats包
通过重命名Decline依赖的Cats类,避免和Spark内置的Cats冲突:
- 确保已添加sbt-assembly插件,在
project/plugins.sbt中:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0")
- 修改
build.sbt,添加Shade规则:
name := "example" version := "0.1" scalaVersion := "2.12.10" libraryDependencies ++= Seq("com.monovore" %% "decline" % "2.3.0") assemblyShadeRules in assembly := Seq( ShadeRule.rename("cats.**" -> "my.cats.@1") .inLibrary("org.typelevel" %% "cats-kernel" % "2.9.0") .inLibrary("org.typelevel" %% "cats-core" % "2.9.0") .inProject )
重新执行sbt assembly构建后,Jar中的Cats类会被重命名到my.cats包下,运行时会优先加载这个重命名后的新版Cats类。
方案2:适配Spark的Cats版本选择Decline版本
Spark 3.x内置的是Cats 1.x,可改用依赖Cats 1.x的Decline 1.x版本,修改build.sbt:
libraryDependencies ++= Seq("com.monovore" %% "decline" % "1.4.0")
注意:Decline 1.x的API和2.x存在差异,需要微调代码适配(比如部分方法的导入或调用方式)。
方案3:强制Spark优先加载用户Jar(不推荐)
启动spark-shell时添加类加载顺序配置,强制优先加载用户Jar的依赖:
spark-shell --jars target/scala-2.12/example-assembly-0.1.jar \ --conf spark.driver.userClassPathFirst=true \ --conf spark.executor.userClassPathFirst=true
该方法可能破坏Spark自身依赖的兼容性,导致其他未知问题,谨慎使用。
内容的提问来源于stack exchange,提问作者Phil
相关产品推荐
相关产品推荐

