Gradle传递依赖版本强制失效:无法指定typesafe config 1.3.3版本
我之前也碰到过类似的Gradle ShadowJar依赖冲突问题,尤其是当引入的依赖本身是fat jar的时候,常规的依赖强制和排除手段经常失效。针对你遇到的geomesa和typesafe config的冲突,我来分享下可行的解决方案:
问题根源分析
你尝试的exclude、constraints、force以及全局resolutionStrategy都无效,大概率是因为geomesa-hbase-spark-runtime_2.11:2.0.1本身是一个fat jar——它内部已经打包了旧版本的com.typesafe:config类。这时候即使你排除了传递依赖,ShadowJar打包时还是会把geomesa jar里的旧config类一起打进去,覆盖你指定的1.3.3版本,导致hasPathOrNull方法找不到的错误。
可行解决方案
方案1:使用Shadow插件的Relocate功能(最可靠)
Relocate可以把你需要的typesafe config类重命名到一个独立的包下,和geomesa自带的旧版本类彻底隔离。修改你的ShadowJar配置:
shadowJar { // 将com.typesafe.config重命名为自定义包名 relocate 'com.typesafe.config', 'shaded.com.typesafe.config' }
这样你的代码会使用重命名后的shaded.com.typesafe.config类,而geomesa内部依然使用它自带的旧版本,两者互不干扰。执行./gradlew shadowJar后,解压生成的jar包就能看到重命名后的包结构。
方案2:调整ShadowJar的打包顺序,优先加载新版本
如果不想使用Relocate,可以尝试让ShadowJar优先打包你指定的1.3.3版本config类,覆盖geomesa里的旧类。配置如下:
shadowJar { // 确保com.typesafe:config:1.3.3被优先处理 dependencies { include(dependency('com.typesafe:config:1.3.3')) } // 调整classpath顺序,把config依赖放在最前面 classpath = configurations.compileClasspath.sort { it.name.contains('config-1.3.3') ? 0 : 1 } }
不过这个方法稳定性稍差,因为依赖顺序可能受其他因素影响,Relocate是更稳妥的选择。
方案3:确认并清理其他潜在的旧版本依赖
再仔细检查一遍所有依赖路径,确保没有其他依赖也引入了旧版本的config。执行以下命令查看完整的依赖树:
./gradlew dependencyInsight --dependency com.typesafe:config --configuration compileClasspath
如果发现其他依赖也带了旧版本,需要对这些依赖也添加exclude配置,或者结合上面的方案一起处理。
验证方法
修改配置后执行./gradlew shadowJar,解压生成的jar包,找到com/typesafe/config/Config.class(或者重命名后的包下的类),用反编译工具查看是否包含hasPathOrNull方法——如果有,说明新版本已经生效。
内容的提问来源于stack exchange,提问作者Georg Heiler

