编译 Spring 5.2 的 spring-core 遇到 Kotlin LinkageError,不一定是业务代码或 Spring 源码写错。IDE 插件、构建插件和依赖中的 Kotlin 类,都可能参与加载,应该先分清报错来自哪条构建链。
类加载约束指向 Sequence
2020 年在 IDEA 中构建时,我遇到的关键错误是:
Error:Kotlin: [Internal Error]
java.lang.LinkageError: loader constraint violation
loader:
org.jetbrains.kotlin.cli.jvm.plugins.PluginURLClassLoader
$SelfThenParentURLClassLoader
previously initiated loading for a different type with name
"kotlin/sequences/Sequence"
原堆栈还经过 Kotlin 脚本发现与编译环境创建。不同加载器中的同名类型不能简单视为同一个类型;这个线索比只看最外层“spring-core 编译失败”更有定位价值。
当时更新的是 IDEA 的 Kotlin 插件
普通插件页面当时没有显示更新按钮,我继续找到下面的 Kotlin 设置入口:
Settings → Languages & Frameworks → Kotlin
下载 1.3.50 并重启 IDEA 后,源码编译恢复。为这个过程折腾了约四天,这是当时环境中的结果,不证明 1.3.50 是所有 Spring 5.2 分支唯一要求,也不是当前项目应回退的版本。
JetBrains 的 1.3.50 发布说明还记录了当时从 Tools 下配置 Kotlin 插件更新的入口。菜单会随 IDE 代际变化,不能把历史路径当作今日固定操作。Kotlin 1.3.50 发布说明
IDE 与项目工具链不要混为一谈
仓库里的 Gradle Kotlin 插件版本、编译器依赖,与 IDEA 的语言支持插件不是同一个配置项。更新 IDE 本体、更新 Kotlin 插件、改 build.gradle,影响范围也不同。
遇到同类错误时,记录 Spring 分支或提交、JDK、Gradle Wrapper、IDEA 和插件版本;比较命令行 Wrapper 构建与 IDE 构建的差异。若只有 IDE 失败,优先检查其编译和委托设置;若两者都失败,再回到仓库声明的依赖与工具链。
每次只改变有依据的变量
旧案例支持“IDE 插件兼容性值得检查”,不支持清空全部缓存、删工程配置或盲目把所有 Kotlin 版本一起升级。先保留错误栈和版本,再按对应版本官方入口处理,结果才具有可解释性。