Kotlin 踩坑 - 为什么组件版本切来切去还是提示NoSuchMethodError

背景

A 组件依赖了 jackson-module-kotlin 2.16.0 版本组件. 项目依赖了 A 组件, 但因为 A 组件的 jackson-module-kotlin 因为兼容问题, 没法用太高的版本, 导致 jackson-module-kotlin 需要降级. 因此在项目里面修改了的 jackson 的组件版本, 降成了2.10. 然后就出现下面的现象.

java 复制代码
Caused by:java.Lang.NoSuchMethodError Create breakpoint com.fasterxml.jackson.module.kotlin.KotlinModule.<init>(IZZZLcom/fasterxml/jackson/module/kotlin/SingletonSupport;
ZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
at com.pinco.plugin.common.serlallzer.ob]ectMapperFactory$companion.buildob]ectMapper(ob]ectMapperFactory.kt:34)
at com.pinco.plugin.common.serializer.ObjectMapperFactory$Companion.accesssbuildobjectMapper(objectMapperFactory.kt:20)
at com.pinco.plugin.common.serializer.objectMapperFactory.<clinit>(objectMapperFactory.kt:21)
at ardServiceImpl.kt:121)

看了一下代码, 报错的地方在这里, 查看源码没发现有编译的问题.

java 复制代码
val objectMapper = ObjectMapper()
    .registerModule(
        KotlinModule() // 这里抛出异常
    )

初步猜想

是 jackson 2.10 版本, 对kotlin还是不友好? 因为项目的 kotlin 版本是 1.3, 怀疑是因为和 kotlin 版本不兼容导致的. 因为 jackson-module-kotlin 是 jackson 的其中一个模块, 版本要一起更新才不会有兼容问题. 因此在项目里面把 jackson 降到2.5, 还是有这个问题, 低于 2.5 版本的 kotlin 版本太高, 用 2.16 jackson 提示 kotlin版本太高, 怎么改都有异常. 最后某次无意间在 A组件 改了 jackson 的版本, 改成 2.10, 竟然没报错了. 但在 A 组件改jackson版本实际上对项目不会有影响的, 因为 A组件已经强制指定了 jackson 版本. 那为什么改了 A组件的版本就没问题的呢?

分析异常原因

根源还是在异常提示那里, noSuchMethodError的方法有点奇怪, KotlinModule 看调用是一个无参的构造方法, 为什么会提示有一堆的参数呢? (IZZZLcom/fasterxml/jackson/module/kotlin/SingletonSupport; ZZZILkotlin/jvm/internal/DefaultConstructorMarker;). 这是因为 KotlinModule 并非有无参构造函数, 而是默认参数隐藏了入参.

A组件 分别用2.16.0和 2.10.0 打包, 反编译, 发现两个版本打包出来的KotlinModule() 是不一样的.

java 复制代码
  // 2.10.0 版本
  ObjectMapper objectMapper = (new ObjectMapper()).registerModule(
      (Module)(new KotlinModule(0, false, false, 7, (DefaultConstructorMarker)null))
  );
  
  // 2.16.0 版本
  ObjectMapper objectMapper = (new ObjectMapper()).registerModule(
      (Module)(new KotlinModule(0, false, false, false, (SingletonSupport)null, false, false, false, 255, (DefaultConstructorMarker)null))
  );
   

虽然看上去没有编译错误, 但实际依赖 jackson 2.16.0 的 A组件上在运行过程会new 11个参数的构造方法. 而项目里面依赖的是 2.10.0, 只有 5个参数的构造方法, 因此会提示找不到 11个参数的构造方法.

结论

这其实是 kotlin 对默认参数的实现导致的. kotlin 底层是字节码, 字节码层面并没有提供对默认参数的实现, 因此kotlin 只能通过编译来支持新特性.

KotlinModule 因为用了默认参数, 会导致不同版本打包出来的字节码会不一样, 因此会导致兼容的问题. 例如 组件A使用了 2.16.0 打包, 并使用了默认方法 项目就只要能用 jackson-module-kotlin 2.16.0, 改了 jackson 版本即使看上去编译没问题, 也可能运行不了.

相关推荐
这里有鱼汤11 分钟前
给你的DeepSeek装上实时行情,让他帮你炒股
后端·python·mcp
咖啡啡不加糖13 分钟前
暴力破解漏洞与命令执行漏洞
java·后端·web安全
风象南16 分钟前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
ん贤35 分钟前
RESTful风格
后端·go·restful
Humbunklung37 分钟前
Rust方法语法:赋予结构体行为的力量
开发语言·后端·rust
萧曵 丶43 分钟前
Rust 内存结构:深入解析
开发语言·后端·rust
Kookoos1 小时前
ABP VNext + Cosmos DB Change Feed:搭建实时数据变更流服务
数据库·分布式·后端·abp vnext·azure cosmos
移动开发者1号1 小时前
Kotlin协程超时控制:深入理解withTimeout与withTimeoutOrNull
android·kotlin