Scala2.12升级至2.13出现未知方法名AbstractMethodError如何解决
这个错误本质是两个兼容问题叠加导致的:
- Scala 2.12与2.13不二进制兼容,你依赖的
com.pack.proj:js-dao是基于2.12编译的,运行在2.13环境下本身就可能出现方法签名不匹配的问题 - 你手动排除了该依赖内置的2.12版本Slick组件,替换为2.13版本的Slick,进一步放大了接口签名的差异
报错中出现的长方法名是Scala编译器为trait中定义的抽象var自动生成的setter方法字节码签名,不需要直接实现这个命名的方法。
1. 优先使用对应Scala版本的官方依赖(最稳妥)
直接查找com.pack.proj是否已经发布了基于Scala 2.13编译的版本,将依赖声明修改为:
"com.pack.proj" % "js-dao_2.13" % ProjVer
不需要排除任何内置Slick依赖,也不需要手动实现任何存根方法,从根源解决二进制兼容问题。
2. 手动实现Scala层面的抽象成员
如果暂时找不到2.13版本的依赖,可以通过声明对应trait的抽象成员让编译器自动生成匹配的字节码方法:
你遇到的com$pack$proj$dao$JSDAO$_setter_$jsDAOApi_$eq方法,对应的是JSDAO trait中定义的抽象成员var jsDAOApi: slick.jdbc.JdbcProfile#API,直接在你的ReceiverDAO类中添加如下声明即可:
override var jsDAOApi: slick.jdbc.JdbcProfile#API = _
如果该成员是val而非var,改为override val jsDAOApi: slick.jdbc.JdbcProfile#API = 你的JdbcProfile实例.api即可,Scala编译器会自动生成匹配字节码签名的get/set方法,不会出现overrides nothing的编译错误。
3. 兜底兼容方案
如果上述方案依然不生效,可以尝试以下操作:
- 不要排除
com.pack.proj依赖的2.12版本Slick组件,在构建配置中同时保留2.12和2.13版本的Slick依赖(仅推荐作为临时验证方案,长期使用可能引发其他类冲突问题) - 使用IDEA、javap等工具反编译
JSDAO的class文件,直接查看其Scala层面的抽象方法签名,按照反编译结果实现对应成员即可。
Scala跨小版本(2.12→2.13)的二进制兼容性非常差,尤其Slick这类大量使用Scala特性的数据库框架,混用不同版本编译的依赖很容易出现各类隐性问题,上述第二、第三种方案仅作为临时过渡使用,建议尽快升级依赖到对应Scala版本的官方构建。
内容的提问来源于stack exchange,提问作者juanchito

