Skip to content
Advertisement

Compilation throws `None of the following functions can be called with the arguments supplied`

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 case org.jooq.JSONB)
  • U is the user type (in this case Any)

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.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement