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

如何在kotlinx.serialization.json.JsonElement与jooq.JSON之间转换?

在kotlinx JsonElement与jOOQ JSON间无字符串序列化转换

当然可以实现。jOOQ的JSON(含JSONB)是JSON字符串的轻量包装,而kotlinx.serialization的JsonElement是内存JSON树结构。要避免显式的字符串序列化/反序列化步骤,可以用以下两种高效方案:

1. 基于CharSequence的直接转换

jOOQ的JSON类实现了CharSequence接口,而kotlinx.serialization的Json解析器支持直接解析CharSequence,无需先调用toString()生成中间字符串:

从jOOQ JSON转kotlinx JsonElement

import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import org.jooq.JSON

fun JSON.toJsonElement(): JsonElement {
    // 直接传入JSON实例(CharSequence),跳过toString()的字符串拷贝
    return Json.decodeFromString(this)
}

从kotlinx JsonElement转jOOQ JSON

通过StringBuilder直接写入JSON内容,避免生成额外的字符串对象:

import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.encodeToWriter
import org.jooq.JSON

fun JsonElement.toJooqJson(): JSON {
    val sb = StringBuilder()
    Json.encodeToWriter(this, sb)
    // 用StringBuilder直接构建jOOQ JSON,减少内存开销
    return JSON.json(sb)
}

2. 自定义jOOQ数据绑定(ORM场景首选)

如果在jOOQ的ORM映射中直接用JsonElement作为实体字段类型,可自定义Binding实现无字符串序列化的数据库交互:

import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import org.jooq.*
import org.jooq.impl.DSL
import java.sql.SQLException
import java.sql.Types

class JsonElementBinding : Binding<JSON, JsonElement> {
    override fun converter(): Converter<JSON, JsonElement> {
        return object : Converter<JSON, JsonElement> {
            override fun from(dbJson: JSON?): JsonElement? {
                return dbJson?.let { Json.decodeFromString(it) }
            }

            override fun to(element: JsonElement?): JSON? {
                return element?.let {
                    val sb = StringBuilder()
                    Json.encodeToWriter(it, sb)
                    JSON.json(sb)
                }
            }

            override fun fromType(): Class<JSON> = JSON::class.java
            override fun toType(): Class<JsonElement> = JsonElement::class.java
        }
    }

    override fun sql(ctx: BindingSQLContext<JsonElement>) {
        ctx.render().visit(DSL.val(ctx.convert(converter()).value())).sql("::json")
    }

    override fun register(ctx: BindingRegisterContext<JsonElement>) {
        ctx.statement().registerOutParameter(ctx.index(), Types.VARCHAR)
    }

    override fun set(ctx: BindingSetStatementContext<JsonElement>) {
        ctx.statement().setString(ctx.index(), ctx.convert(converter()).value()?.data())
    }

    override fun set(ctx: BindingSetSQLOutputContext<JsonElement>) {
        throw SQLException("Not supported")
    }

    override fun get(ctx: BindingGetResultSetContext<JsonElement>) {
        ctx.convert(converter()).value(JSON.json(ctx.resultSet().getString(ctx.index())))
    }

    override fun get(ctx: BindingGetStatementContext<JsonElement>) {
        ctx.convert(converter()).value(JSON.json(ctx.statement().getString(ctx.index())))
    }

    override fun get(ctx: BindingGetSQLInputContext<JsonElement>) {
        throw SQLException("Not supported")
    }
}

使用时在实体表定义中指定绑定:

import org.jooq.TableField
import org.jooq.impl.TableImpl

data class MyEntity(
    val id: Long,
    val data: JsonElement
)

class MyEntityTable(name: String = "my_entity") : TableImpl<MyEntityRecord>(name) {
    val ID: TableField<MyEntityRecord, Long> = createField("id", SQLDataType.BIGINT.notNull())
    val DATA: TableField<MyEntityRecord, JsonElement> = createField(
        "data",
        SQLDataType.JSON,
        this,
        "",
        JsonElementBinding()
    )
}

关键说明

这里的“无字符串序列化”指避免显式的中间字符串对象创建与拷贝(比如jsonElement.toString()再转jOOQ JSON)。jOOQ的JSON类本身基于字符串包装,底层仍依赖JSON字符串,但上述方案通过CharSequence兼容、StringBuilder直接写入等方式,大幅减少了不必要的内存开销。

内容的提问来源于stack exchange,提问作者Emre

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 03:32:46