With provideDelegate
feature and unchecked cast I was able to make it as a universal solution:
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class Person {
var name: String by DaoProperty()
var address: String? by DaoProperty()
var age: Int by DaoProperty()
var height: Int? by DaoProperty()
}
class DaoProperty<T> {
operator fun provideDelegate(thisRef: Any, property: KProperty<*>): ReadWriteProperty<Any, T> {
val result: Any = if (property.returnType.isMarkedNullable) NullableDaoProperty<T>() else NotNullDaoProperty<T>()
@Suppress("UNCHECKED_CAST")
return result as ReadWriteProperty<Any, T>
}
}
private class NotNullDaoProperty<T> : ReadWriteProperty<Any, T> {
private var value: T? = null
override fun getValue(thisRef: Any, property: KProperty<*>): T {
if (value == null) throw UninitializedPropertyAccessException(property.name)
return value!!
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
this.value = value
}
}
private class NullableDaoProperty<T> : ReadWriteProperty<Any, T?> {
private var value: T? = null
private var initialized = false
override fun getValue(thisRef: Any, property: KProperty<*>): T? {
if (!initialized) throw UninitializedPropertyAccessException(property.name)
return value
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T?) {
this.value = value
this.initialized = true
}
}