Trying to implement a custom JSONB binding that maps to an object containing a map. Generated code throws a None of the following functions can be called with the arguments supplied
error caused by the following line:
val SOME_FIELD: TableField<SomeRecord, Jsonb?> = createField(DSL.name("meta"), SQLDataType.JSONB.nullable(false).defaultValue(DSL.field("'{}'::jsonb", SQLDataType.JSONB)), this, "", JsonbBinding())
Here’s my configuration:
class JsonbBinding : Binding<Any, Jsonb> { private val mapper = ObjectMapper() override fun converter(): Converter<Any, Jsonb> { return object : Converter<Any, Jsonb> { override fun from(dbObject: Any?): Jsonb { if (dbObject == null) return Jsonb() val props = mapper.readValue<MutableMap<String, Any>>(dbObject.toString()) return Jsonb(props) } override fun to(userObject: Jsonb?): Any? { return mapper.writeValueAsString(userObject) } override fun fromType(): Class<Any> { return Any::class.java } override fun toType(): Class<Jsonb> { return Jsonb::class.java } } } override fun sql(ctx: BindingSQLContext<Jsonb>) { ctx.render()?.let { if (it.paramType() == ParamType.INLINED) { it.visit( DSL.inline(ctx.convert(converter()).value()) ).sql("::jsonb") } else { it.sql("?::jsonb") } } } override fun register(ctx: BindingRegisterContext<Jsonb>) { ctx.statement().registerOutParameter(ctx.index(), Types.VARCHAR) } override fun set(ctx: BindingSetStatementContext<Jsonb>) { ctx.statement().setString( ctx.index(), ctx.convert(converter()).value()?.toString() ) } override fun set(ctx: BindingSetSQLOutputContext<Jsonb>) { throw SQLFeatureNotSupportedException() } override fun get(ctx: BindingGetResultSetContext<Jsonb>) { ctx.convert(converter()).value(ctx.resultSet().getString(ctx.index())) } override fun get(ctx: BindingGetStatementContext<Jsonb>) { ctx.convert(converter()).value(ctx.statement().getString(ctx.index())) } override fun get(ctx: BindingGetSQLInputContext<Jsonb>) { throw SQLFeatureNotSupportedException() } }
<forcedType> <userType>org.example.Jsonb</userType> <binding>org.example.JsonbBinding</binding> <includeExpression>.*</includeExpression> <includeTypes>jsonb</includeTypes> </forcedType>
Also, it seems like the line causing problems is mapping database data to JOOQ’s default JSONB object. Is that what’s causing the issue? Is there anything I may want to do about it? Is there some other way of doing mapping database JSONB data to a map by JOOQ?
Advertisement
Answer
I think you’re confusing the type variables on Binding<T, U>
here:
T
is the database / JDBC type (in this caseorg.jooq.JSONB
)U
is the user type (in this caseAny
)
You have to implement the binding the other way round: Binding<JSONB?, Any?>
. Since jOOQ already takes care of properly binding the JSONB
type to JDBC, you can probably do with your Converter<JSONB?, Any?>
implementation alone, and attach that to your generated code instead:
class JsonbConverter : Converter<JSONB?, Any?> { ... }
Also, you don’t have to use your own Jsonb
type to wrap JSON data here.