Можно-ли в kotlin делегировать свойство другому свойству, если оно так же делегировано?

Игрался я тут с ORM exposed и столкнулся с одной проблемой, при реализации наследования, через агрегацию. Если, например, написать так (пример совершенно выдуманный):

data class AEntity(val _id : EntityID<UUID>) : UUIDEntity(_id) {
    companion object : UUIDEntityClass<AEntity>(ATable)
    val b by BEntity optionalBackReferencedOn BTable.id
    var text1 : String by ATable.text1
    override fun toString(): String {
        return "AEntity(_id=$_id, text1='$text1')"
    }

}

data class BEntity(val _id : EntityID<UUID>) : UUIDEntity(_id) {
    companion object : UUIDEntityClass<BEntity>(BTable)
    var a : AEntity by AEntity referencedOn BTable.id
    var int1 : Int by BTable.int1
    var text1 : String by a::text1

    override fun toString(): String {
        return "BEntity(_id=$_id, a=$a, int1=$int1, text1='$text1')"
    }
}

То выборка экземпляров BEntity из таблицы сопровождалась ошибкой, по причине того, что поле var a : AEntity само делегировано и на момент конструирования делегировать ему ещё и var text1 : String by a::text1 не получится, так как оно банально не инициализировано.

Сам я нашёл решение только в виде такого вот хитрого делегата, который, как бы, откладывает обращение к свойству var a : AEntity до того момента, как он реально понадобится. Но такое решение я не считаю самым лучшим, ибо оно добавляет лишний холостой вызов функции.

abstract class Late<TValue, TEntity>(inline val kMutableProperty0: ()-> KMutableProperty0<TValue>) :
    ReadWriteProperty<TEntity, TValue> {
    override fun setValue(thisRef: TEntity, property: KProperty<*>, value: TValue) {
        kMutableProperty0().setValue(thisRef, property, value)
    }

    override fun getValue(thisRef: TEntity, property: KProperty<*>): TValue {
        return kMutableProperty0().getValue(thisRef, property)
    }
}

inline fun <reified TValue, reified TEntity> late(noinline kMutableProperty0: ()-> KMutableProperty0<TValue>) =
    object : Late<TValue, TEntity>(kMutableProperty0) {}



data class AEntity(val _id : EntityID<UUID>) : UUIDEntity(_id) {
    companion object : UUIDEntityClass<AEntity>(ATable)
    val b by BEntity optionalBackReferencedOn BTable.id
    var text1 : String by ATable.text1
    override fun toString(): String {
        return "AEntity(_id=$_id, text1='$text1')"
    }

}

data class BEntity(val _id : EntityID<UUID>) : UUIDEntity(_id) {
    companion object : UUIDEntityClass<BEntity>(BTable)
    var a : AEntity by AEntity referencedOn BTable.id
    var int1 : Int by BTable.int1
    var text1 : String by late { a::text1 }

    override fun toString(): String {
        return "BEntity(_id=$_id, a=$a, int1=$int1, text1='$text1')"
    }
}

Если кто знает решение без этих вот танцев с бубном, поделитесь пожалуйста.

Дополнено 16.03.2021 в 11:45

У предыдущего решения нашёлся один неприятный момент - оно работало только для ReadWrite свойств. Следующий вариант, вроде бы, работает и для ReadOnly.

abstract class LateR<TValue, TEntity>(inline val kProperty0: ()-> KProperty0<TValue>) :
    ReadOnlyProperty<TEntity, TValue> {

    override operator fun getValue(thisRef: TEntity, property: KProperty<*>): TValue {
        return kProperty0().getValue(thisRef, property)
    }
}

abstract class LateRW<TValue, TEntity>(inline val kMutableProperty0: ()-> KMutableProperty0<TValue>) :
    LateR<TValue, TEntity>(kMutableProperty0), ReadWriteProperty<TEntity, TValue> {
    override operator fun setValue(thisRef: TEntity, property: KProperty<*>, value: TValue) {
        kMutableProperty0().setValue(thisRef, property, value)
    }
}

inline fun <reified TValue, reified TEntity> lateRW(noinline kMutableProperty0: ()-> KMutableProperty0<TValue>) =
    object : LateRW<TValue, TEntity>(kMutableProperty0) {}

inline fun <reified TValue, reified TEntity> lateR(noinline kProperty0: ()-> KProperty0<TValue>) =
    object : LateR<TValue, TEntity>(kProperty0) {}

Кстати, если кто знает, как сделать так, что бы функции lateR и lateRW можно было назвать одинаково, то, также, прошу подсказать.


Ответы (0 шт):