You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级jOOQ至3.18后MockK无法模拟其类(3.14版本正常)

jOOQ升级至3.15+后MockK无法模拟TableImpl类的问题

问题背景

我负责的Kotlin项目使用jOOQ与数据库交互,通过jOOQ生成表、字段等Java元模型类,单元测试中用MockK模拟jOOQ的部分类。

简化测试代码如下:

@Test
fun `should throw exception for nonexistent fields`() {
    // given
    val table = mockk<TableImpl<*>>()
    every { table.field(any<String>()) } returns null
    every { table.name } returns "table-name"

    // when
    // then
}

升级后的报错

将jOOQ从3.14升级到3.18后,MockK无法模拟jOOQ类,报错信息如下:

[io.moc.imp.JvmMockKGateway] (main) Starting JVM MockK implementation. Java version = 11.0.18. 
[io.moc.pro.jvm.JvmMockKAgentFactory] (main) Byte buddy agent installed
[io.moc.pro.jvm.dis.BootJarLoader] (main) Bootstrap class loaded io.mockk.proxy.jvm.dispatcher.JvmMockKDispatcher
[io.moc.pro.jvm.dis.BootJarLoader] (main) Bootstrap class loaded io.mockk.proxy.jvm.dispatcher.JvmMockKWeakMap
[io.moc.pro.jvm.dis.BootJarLoader] (main) Bootstrap class loaded io.mockk.proxy.jvm.dispatcher.JvmMockKWeakMap$StrongKey
[io.moc.pro.jvm.dis.BootJarLoader] (main) Bootstrap class loaded io.mockk.proxy.jvm.dispatcher.JvmMockKWeakMap$WeakKey
[io.moc.imp.ins.AbstractMockFactory] (main) Creating mockk for TableImpl name=#1
[io.moc.imp.ins.AbstractMockFactory] (main) Building proxy for TableImpl hashcode=58a4a74d
[io.moc.pro.jvm.tra.JvmInlineInstrumentation] (main) Retransforming [Ljava.lang.Class;@6f3f0fae
[io.moc.pro.jvm.tra.JvmInlineInstrumentation] (main) Failed to transform classes [
class org.jooq.impl.TableImpl, 
interface org.jooq.impl.ScopeMappable, 
interface org.jooq.QueryPartInternal, 
interface org.jooq.QueryPart, 
interface java.io.Serializable, 
interface org.jooq.impl.ScopeNestable, 
interface org.jooq.impl.SimpleCheckQueryPart, 
interface org.jooq.impl.QOM$UNotYetImplemented, 
interface org.jooq.impl.QOM$UEmpty, 
class org.jooq.impl.AbstractTable, 
interface org.jooq.Table, 
interface org.jooq.TableLike, 
interface org.jooq.Fields, 
interface org.jooq.RecordQualifier, 
interface org.jooq.Qualified, 
interface org.jooq.Named, 
interface org.jooq.GroupField, 
interface org.jooq.SelectField, 
interface org.jooq.SelectFieldOrAsterisk, 
interface org.jooq.Typed, 
interface org.jooq.impl.FieldsTrait, 
interface org.jooq.impl.QOM$Aliasable, 
class org.jooq.impl.AbstractNamed, 
class org.jooq.impl.AbstractQueryPart, 
class java.lang.Object
]: java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a method
    at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
    at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:167)
    at io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation.retransform(JvmInlineInstrumentation.kt:28)
    at io.mockk.proxy.common.transformation.RetransformInlineInstrumentation$execute$1.invoke(RetransformInlineInstrumentation.kt:19)
    at io.mockk.proxy.common.transformation.RetransformInlineInstrumentation$execute$1.invoke(RetransformInlineInstrumentation.kt:16)
    at io.mockk.proxy.common.transformation.ClassTransformationSpecMap.applyTransformation(ClassTransformationSpecMap.kt:41)
    at io.mockk.proxy.common.transformation.RetransformInlineInstrumentation.execute(RetransformInlineInstrumentation.kt:16)
    at io.mockk.proxy.jvm.ProxyMaker.inline(ProxyMaker.kt:88)
    at io.mockk.proxy.jvm.ProxyMaker.proxy(ProxyMaker.kt:30)
    at io.mockk.impl.instantiation.JvmMockFactory.newProxy(JvmMockFactory.kt:34)
    at io.mockk.impl.instantiation.AbstractMockFactory.newProxy$default(AbstractMockFactory.kt:24)
    at io.mockk.impl.instantiation.AbstractMockFactory.mockk(AbstractMockFactory.kt:59)
    at my-test-here

jOOQ的代码变更导致MockK无法修改类以生成模拟对象/代理,目前尚未明确MockK具体要执行的修改操作。MockK的issue追踪器中有类似问题,但原因仍不明确。我对比了jOOQ 3.14到3.18版本间TableImpl的变更,未发现明显异常。

问题定位

搭建重现项目后发现,问题从jOOQ 3.14.16升级到3.15版本时开始出现。

MockK的跟踪日志给出了关键线索:
jOOQ 3.14.16版本日志:

...
[io.mockk.impl.instantiation.AbstractMockFactory] (main) Creating mockk for TableImpl name=#1
[io.mockk.impl.instantiation.AbstractMockFactory] (main) Building proxy for TableImpl hashcode=290b1b2e
[io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation] (main) Retransforming [Ljava.lang.Class;@7d755813
[io.mockk.proxy.common.ProxyMaker] (main) Taking instance of class org.jooq.impl.TableImpl itself because it is not abstract and no additional interfaces specified.
[io.mockk.proxy.common.ProxyMaker] (main) Instantiating proxy for class org.jooq.impl.TableImpl via instantiator
...

jOOQ 3.15.0版本日志:

[io.mockk.impl.instantiation.AbstractMockFactory] (main) Creating mockk for TableImpl name=#1
[io.mockk.impl.instantiation.AbstractMockFactory] (main) Building proxy for TableImpl hashcode=6fff253c
[io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation] (main) Retransforming [Ljava.lang.Class;@72fe8a4f
[io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation] (main) Failed to transform classes 

在3.14.16版本中,MockK不需要为TableImpl构建代理,因为它是非抽象类且未指定额外接口,直接通过实例化器创建实例即可。

目前该问题已提交至MockK的issue。


内容的提问来源于stack exchange,提问作者Marcel Stör

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 08:39:55