Search code examples
kotlinreflectiontype-safety

Kotlin - reflection and type safety


I am writing a small library for programatically generating SQL queries. The goal is that the API of this library can be used like that:

myQuery.where(
    MyClass::id equal "foo",
    MyClass::age notEqual 55 
).findAll()

The signatures of both the where function, and the infix operators is under my control. Here are the relevant definitions that I have at the moment:

interface KpaFilter<BASE, FIELD>

infix fun <BASE: Any, FIELD: Any> KProperty1<BASE, FIELD>.equal(value: FIELD): KpaFilter<BASE, FIELD> { ... }

fun <BASE: Any> where(vararg filters: KpaFilter<BASE, *>?): KpaQuery<BASE>

Still, I cannot find a proper way to make this type safe. For example, I would like this to raise a compilation error, but unfortunately, it compiles:

val someFilter = MyClass::id equal 55 // id is a string

Is it possible to somehow modify the signatures of the declarations above and achieve this kind of type safety, without making the API more cumbersome than its current form?


Solution

  • If you don't mind using Kotlin internal APIs, there is a hidden feature in the compiler which does exactly this. The feature is enabled by annotating a parameter with @kotlin.internal.Exact:

    @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
    infix fun <BASE: Any, FIELD: Any> KProperty1<BASE, @kotlin.internal.Exact FIELD>.equal(value: FIELD): KpaFilter<BASE, FIELD> { ... }
    

    This works pretty well and can be used in regular Kotlin projects. Of course, we don't have guarantees it will be supported in the future.