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

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?

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.

Related

Custom lint rule kotlin object

I'm trying to create a custom lint rule in order to avoid using a kotlin object class.
object AColors {
val white: Color = Color(0xFFFFFFFF)
}
fun main() {
val myColor = AColors.white //Lint error : Do not use AColors
}
How can I manage to get a lint issue when AColors is used?
In my case, AColors can't be private because I need it for a specific case.
I tried to create a custom lint rule to check the import but this is not a bullet-proof solution as you can use AColors without importing anything
class InvalidImportHandler(private val context: JavaContext) : UElementHandler() {
override fun visitImportStatement(node: UImportStatement) {
//check the import
}
}
For this specific case, you may check for USimpleNameReferenceExpressions and then check if the reference is to the AColors class. Like so:
class AColorsReferenceDetector : Detector(), Detector.UastScanner {
override fun getApplicableUastTypes(): List<Class<out UElement>> {
return listOf(USimpleNameReferenceExpression::class.java)
}
override fun createUastHandler(context: JavaContext): UElementHandler {
return object : UElementHandler() {
override fun visitSimpleNameReferenceExpression(
node: USimpleNameReferenceExpression
) {
val element = node.resolve()?.unwrapped
if (element is KtObjectDeclaration && element.name == "AColors") {
context.report(
ISSUE,
node,
context.getLocation(node.uastParent)
)
}
}
}
}
companion object {
val ISSUE = Issue.create(
AColorsReferenceDetector::class.simpleName.orEmpty(),
"Do not use AColors",
"Do not use AColors",
Category.CORRECTNESS,
10,
Severity.ERROR,
Implementation(
AColorsReferenceDetector::class.java,
EnumSet.of(Scope.JAVA_FILE)
)
)
}
}
Example IssueRegistry:
class IssueRegistry : IssueRegistry() {
override val api = CURRENT_API
override val minApi: Int
get() = 8
override val vendor: Vendor = Vendor()
override val issues
get() = listOf(AColorsReferenceDetector.ISSUE)
}
Example result:

Kotlinx Serialization, inlining sealed class/interface [duplicate]

This question already has an answer here:
kotlinx deserialization: different types && scalar && arrays
(1 answer)
Closed 7 months ago.
With a structure similar to the following:
#Serializable
sealed class Parameters
#Serializable
data class StringContainer(val value: String): Parameters()
#Serializable
data class IntContainer(val value: Int): Parameters()
#Serializable
data class MapContainer(val value: Map<String, Parameters>): Parameters()
// more such as list, bool and other fairly (in the context) straight forward types
And the following container class:
#Serializable
data class PluginConfiguration(
// other value
val parameters: Parameters.MapContainer,
)
I want to reach a (de)serialization where the paramters are configured as a flexible json (or other) map, as one would usually expect:
{
"parameters": {
"key1": "String value",
"key2": 12,
"key3": {}
}
}
And so on. Effectively creating a flexible structure that is still structured enough to not be completely uncontrolled as Any would be. There's a fairly clearly defined (de)serialization, but I cannot figure how to do this.
I've tried reading the following
https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md
And I do have a hunch that a polymorphic serializer is needed, but so far I'm bumping in to either generic structures, which I believe is way overkill for my purpose or that it for some reason cannot find the serializer for my subclasses, when writing a custom serializer for Parameters.
Update
So using custom serializers combined with surrogate classes, most things are working. The current problem is when values are put into the map, I get a kotlin.IllegalStateException: Primitives cannot be serialized polymorphically with 'type' parameter. You can use 'JsonBuilder.useArrayPolymorphism' instead. Even when I enable array polymorphism this error arises
The answer with kotlinx deserialization: different types && scalar && arrays is basically the answer, and the one I will accept. However, for future use, the complete code to my solution is as follows:
Class hierarchy
#kotlinx.serialization.Serializable(with = ParametersSerializer::class)
sealed interface Parameters
#kotlinx.serialization.Serializable(with = IntContainerSerializer::class)
data class IntContainer(
val value: Int
) : Parameters
#kotlinx.serialization.Serializable(with = StringContainerSerializer::class)
data class StringContainer(
val value: String
) : Parameters
#kotlinx.serialization.Serializable(with = MapContainerSerializer::class)
data class MapContainer(
val value: Map<String, Parameters>
) : Parameters
#kotlinx.serialization.Serializable
data class PluginConfiguration(
val plugin: String,
val parameters: MenuRunnerTest.MapContainer
)
Serializers:
abstract class BaseParametersSerializer<T : Parameters> : KSerializer<T> {
override val descriptor: SerialDescriptor = JsonElement.serializer().descriptor
override fun serialize(encoder: Encoder, value: T) {
fun toJsonElement(value: Parameters): JsonElement = when (value) {
is IntContainer -> JsonPrimitive(value.value)
is MapContainer -> JsonObject(
value.value.mapValues { toJsonElement(it.value) }
)
is StringContainer -> JsonPrimitive(value.value)
}
val sur = toJsonElement(value)
encoder.encodeSerializableValue(JsonElement.serializer(), sur)
}
override fun deserialize(decoder: Decoder): T {
with(decoder as JsonDecoder) {
val jsonElement = decodeJsonElement()
return deserializeJson(jsonElement)
}
}
abstract fun deserializeJson(jsonElement: JsonElement): T
}
object ParametersSerializer : BaseParametersSerializer<Parameters>() {
override fun deserializeJson(jsonElement: JsonElement): Parameters {
return when(jsonElement) {
is JsonPrimitive -> when {
jsonElement.isString -> StringContainerSerializer.deserializeJson(jsonElement)
else -> IntContainerSerializer.deserializeJson(jsonElement)
}
is JsonObject -> MapContainerSerializer.deserializeJson(jsonElement)
else -> throw IllegalArgumentException("Only ints, strings and strings are allowed here")
}
}
}
object StringContainerSerializer : BaseParametersSerializer<StringContainer>() {
override fun deserializeJson(jsonElement: JsonElement): StringContainer {
return when(jsonElement) {
is JsonPrimitive -> StringContainer(jsonElement.content)
else -> throw IllegalArgumentException("Only strings are allowed here")
}
}
}
object IntContainerSerializer : BaseParametersSerializer<IntContainer>() {
override fun deserializeJson(jsonElement: JsonElement): IntContainer {
return when (jsonElement) {
is JsonPrimitive -> IntContainer(jsonElement.int)
else -> throw IllegalArgumentException("Only ints are allowed here")
}
}
}
object MapContainerSerializer : BaseParametersSerializer<MapContainer>() {
override fun deserializeJson(jsonElement: JsonElement): MapContainer {
return when (jsonElement) {
is JsonObject -> MapContainer(jsonElement.mapValues { ParametersSerializer.deserializeJson(it.value) })
else -> throw IllegalArgumentException("Only maps are allowed here")
}
}
}
This structure should be expandable for lists, doubles and other structures, not included in the example :)

Implementing observable properties that can also serialize in Kotlin

I'm trying to build a class where certain values are Observable but also Serializable.
This obviously works and the serialization works, but it's very boilerplate-heavy having to add a setter for every single field and manually having to call change(...) inside each setter:
interface Observable {
fun change(message: String) {
println("changing $message")
}
}
#Serializable
class BlahVO : Observable {
var value2: String = ""
set(value) {
field = value
change("value2")
}
fun toJson(): String {
return Json.encodeToString(serializer(), this)
}
}
println(BlahVO().apply { value2 = "test2" })
correctly outputs
changing value2
{"value2":"test2"}
I've tried introducing Delegates:
interface Observable {
fun change(message: String) {
println("changing $message")
}
#Suppress("ClassName")
class default<T>(defaultValue: T) {
private var value: T = defaultValue
operator fun getValue(observable: Observable, property: KProperty<*>): T {
return value
}
operator fun setValue(observable: Observable, property: KProperty<*>, value: T) {
this.value = value
observable.change(property.name)
}
}
}
#Serializable
class BlahVO : Observable {
var value1: String by Observable.default("value1")
fun toJson(): String {
return Json.encodeToString(serializer(), this)
}
}
println(BlahVO().apply { value1 = "test1" }) correctly triggers change detection, but it doesn't serialize:
changing value1
{}
If I go from Observable to ReadWriteProperty,
interface Observable {
fun change(message: String) {
println("changing $message")
}
fun <T> look(defaultValue: T): ReadWriteProperty<Observable, T> {
return OP(defaultValue, this)
}
class OP<T>(defaultValue: T, val observable: Observable) : ObservableProperty<T>(defaultValue) {
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
super.setValue(thisRef, property, value)
observable.change("blah!")
}
}
}
#Serializable
class BlahVO : Observable {
var value3: String by this.look("value3")
fun toJson(): String {
return Json.encodeToString(serializer(), this)
}
}
the result is the same:
changing blah!
{}
Similarly for Delegates.vetoable
var value4: String by Delegates.vetoable("value4", {
property: KProperty<*>, oldstring: String, newString: String ->
this.change(property.name)
true
})
outputs:
changing value4
{}
Delegates just doesn't seem to work with Kotlin Serialization
What other options are there to observe a property's changes without breaking its serialization that will also work on other platforms (KotlinJS, KotlinJVM, Android, ...)?
Serialization and Deserialization of Kotlin Delegates is not supported by kotlinx.serialization as of now.
There is an open issue #1578 on GitHub regarding this feature.
According to the issue you can create an intermediate data-transfer object, which gets serialized instead of the original object. Also you could write a custom serializer to support the serialization of Kotlin Delegates, which seems to be even more boilerplate, then writing custom getters and setters, as proposed in the question.
Data Transfer Object
By mapping your original object to a simple data transfer object without delegates, you can utilize the default serialization mechanisms.
This also has the nice side effect to cleanse your data model classes from framework specific annotations, such as #Serializable.
class DataModel {
var observedProperty: String by Delegates.observable("initial") { property, before, after ->
println("""Hey, I changed "${property.name}" from "$before" to "$after"!""")
}
fun toJson(): String {
return Json.encodeToString(serializer(), this.toDto())
}
}
fun DataModel.toDto() = DataTransferObject(observedProperty)
#Serializable
class DataTransferObject(val observedProperty: String)
fun main() {
val data = DataModel()
println(data.toJson())
data.observedProperty = "changed"
println(data.toJson())
}
This yields the following result:
{"observedProperty":"initial"}
Hey, I changed "observedProperty" from "initial" to "changed"!
{"observedProperty":"changed"}
Custom data type
If changing the data type is an option, you could write a wrapping class which gets (de)serialized transparently. Something along the lines of the following might work.
#Serializable
class ClassWithMonitoredString(val monitoredProperty: MonitoredString) {
fun toJson(): String {
return Json.encodeToString(serializer(), this)
}
}
fun main() {
val monitoredString = obs("obsDefault") { before, after ->
println("""I changed from "$before" to "$after"!""")
}
val data = ClassWithMonitoredString(monitoredString)
println(data.toJson())
data.monitoredProperty.value = "obsChanged"
println(data.toJson())
}
Which yields the following result:
{"monitoredProperty":"obsDefault"}
I changed from "obsDefault" to "obsChanged"!
{"monitoredProperty":"obsChanged"}
You however lose information about which property changed, as you don't have easy access to the field name. Also you have to change your data structures, as mentioned above and might not be desirable or even possible. In addition, this work only for Strings for now, even though one might make it more generic though.
Also, this requires a lot of boilerplate to start with. On the call site however, you just have to wrap the actual value in an call to obs.
I used the following boilerplate to get it to work.
typealias OnChange = (before: String, after: String) -> Unit
#Serializable(with = MonitoredStringSerializer::class)
class MonitoredString(initialValue: String, var onChange: OnChange?) {
var value: String = initialValue
set(value) {
onChange?.invoke(field, value)
field = value
}
}
fun obs(value: String, onChange: OnChange? = null) = MonitoredString(value, onChange)
object MonitoredStringSerializer : KSerializer<MonitoredString> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("MonitoredString", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: MonitoredString) {
encoder.encodeString(value.value)
}
override fun deserialize(decoder: Decoder): MonitoredString {
return MonitoredString(decoder.decodeString(), null)
}
}

Pass different functions with different method signatures to a function as a parameter in kotlin

I am working on an android application using kotlin as my primary language. I needed to ask some runtime permissions for some parts of the app. So instead of writing similar boilerplate code to ask for the permissions I decided to to write a separate static function that checks for the permission, and run a method. Here is the static function
fun permissionExecution(childFragment: Fragment, permission: String, expression: ????) {
Dexter.withActivity(childFragment.requireActivity())
.withPermission(permission)
.withListener(object : PermissionListener {
override fun onPermissionGranted(response: PermissionGrantedResponse?) {
expression()
}
override fun onPermissionRationaleShouldBeShown(
permission: PermissionRequest?,
token: PermissionToken
) {
token.continuePermissionRequest()
}
override fun onPermissionDenied(response: PermissionDeniedResponse) {
if(response.isPermanentlyDenied) {
openSettings(childFragment)
}
}
}).check()
}
This code works perfectly when I passed in methods with no arguments. But I have some situations where I will like to pass in methods with different arguments types.
calling the method like this permissionExecution(childfragment, permission, foo(string))
calling the same method like this permissionExecution(childfrgment, permission, bas(string, Int))
what class type can I use for the espression argument in the permissionExecution() method
It doesn't make sense to include the function parameters in the definition of the lambda arument. You already have everything you need to call these other functions:
permissionExecution(myFragment, Manifest.permission.RECORD_AUDIO) {
foo(myString)
}
permissionExecution(myFragment, Manifest.permission.CAMERA) {
bar(myString, myInt)
}
If you need the PermissionGrantedResponse to determine what these parameters are, you can define that as the function input:
fun permissionExecution(childFragment: Fragment, permission: String, expression: (PermissionGrantedResponse) -> Unit) {
Dexter.withActivity(childFragment.requireActivity())
.withPermission(permission)
.withListener(object : PermissionListener {
override fun onPermissionGranted(response: PermissionGrantedResponse) {
expression(response)
}
//...
}
//...
permissionExecution(myFragment, Manifest.permission.RECORD_AUDIO) { response ->
foo(response.permissionName)
}
If I understand correctly, you have implemented a common static func that checks permission and pass some lambda to it that will be invoked when permission is granted. I do not understand why you these lambdas need some argument parameters. Is the below implementation what you desire?
class CameraFragment {
fun onCreateView() {
permissionExecution(childFragment = arg1, permission = "perm", expression = {
// open camera
})
}
}
class LocationActivity {
fun onCreate() {
permissionExecution(childFragment = arg1, permission = "perm", expression = {
fetchLocation()
})
}
fun fetchLocation() {
// get location, do stuff
}
}
here is a not so elegant solution. I create a wrapper class with a single method interface like this
class Permissions(val childFragment: Fragment, private val permission: String, val runExpression: RunExpression) {
interface RunExpression{
fun expression()
}
fun permissionExecution() {
Dexter.withActivity(childFragment.requireActivity())
.withPermission(permission)
.withListener(object : PermissionListener {
override fun onPermissionGranted(response: PermissionGrantedResponse?) {
runExpression.expression()
}
override fun onPermissionRationaleShouldBeShown(
permission: PermissionRequest?,
token: PermissionToken
) {
token.continuePermissionRequest()
}
override fun onPermissionDenied(response: PermissionDeniedResponse) {
if(response.isPermanentlyDenied) {
openSettings(childFragment)
}
}
}).check()
}
}
then call the class like this each time I need the permission
1.
Permissions(this, Manifest.permission.READ_CONTACTS, object : Permissions.RunExpression {
override fun expression() {
startActivityForResult(intent, PICK_CONTACT)
}
}).permissionExecution()
2.
Permissions(this, Manifest.permission.READ_CONTACTS, object : Permissions.RunExpression {
override fun expression() {
writeFileToLocation(file, locationPath)
}
}).permissionExecution()
a better way i find by adapting the solution here is firstly, create an interface like this
interface RunExpression{
fun expression()}
then use the interface in the function signature
fun permissionExecution(childFragment: Fragment, permission : String, runExpression: RunExpression) {
Dexter.withActivity(childFragment.requireActivity())
.withPermission(permission)
.withListener(object : PermissionListener {
override fun onPermissionGranted(response: PermissionGrantedResponse?) {
runExpression.expression()
}
override fun onPermissionRationaleShouldBeShown(
permission: PermissionRequest?,
token: PermissionToken
) {
token.continuePermissionRequest()
}
override fun onPermissionDenied(response: PermissionDeniedResponse) {
if(response.isPermanentlyDenied) {
openSettings(childFragment)
}
}
}).check()}
then wherever I want to call the function, I save the anonymous object that implement the interface into a variable
val startMyActivity = object : RunExpression {
override fun expression() {
startActivityForResult(intent, PICK_CONTACT)
}
}
then call the function with the variable
permissionExecution(this, Manifest.permission.READ_CONTACTS, startMyActivity)

Runtime polymorphism in Kotlin

Is there any elegant way to apply polymorphism in this case? The parser provides the following classes at runtime:
class io.swagger.v3.oas.models.media.Schema //is parent of the rest :
class io.swagger.v3.oas.models.media.ComposedSchema
class io.swagger.v3.oas.models.media.ArraySchema
class io.swagger.v3.oas.models.media.StringSchema
class io.swagger.v3.oas.models.media.ObjectSchema
I'd like to have function for each class with the same name and simple, short method which will cast and call necessary function at runtime. Which is actually happening, but I hope there is more brief solution, without necessity of making this kind of duplicates:
fun main() {
val parser = OpenAPIV3Parser()
val asList = listOf(pathYaml3, pathYml2)
val map = asList.map(parser::read)
.flatMap { it.components.schemas.values }
.forEach(::parseRawSchema)
}
fun parseRawSchema(schema: Schema<Any>) {
if (schema is ComposedSchema) {
parseSchema(schema)
}
if (schema is StringSchema) {
parseSchema(schema)
}
...
}
fun parseSchema(schema: ComposedSchema) {
println("Compose-schema")
}
fun parseSchema(schema: StringSchema) {
println("Sting-schema")
}
...
Try use extension.
For example:
fun ComposedSchema.parseSchema() {
println("Compose-schema")
}
fun StringSchema.parseSchema() {
println("Sting-schema")
}
And than:
fun parseRawSchema(schema: Schema<Any>) {
schema.parseSchema()
}