I want to create a String representation of the path from a root element A through it's declared member properties, until I get to a specific leaf element, using Kotlin member references. To clarify, suppose I have a class structure like this:
data class A (val propB: B)
data class B (val propC: C)
data class C (val propD: D, val propE: E)
In the end, I want to create a String which contains for example: propB.propC.propD
, or propB.propC.propE
. It's basically the same concept as JSONPath.
The context of this relation is known at compile time, so it could be hard coded directly, but this would fail if one of these properties gets renamed during a refactoring, so I want to use a programmatic approach with direct references.
I can access the first "level" of this hierarchy by using A::propB.name
, which will simply print propB
. However, I can't find a good way to chain these calls, since A::propB::propC.name
etc. is invalid code.
I tried to write a Builder class to help me chain these references together, but it doesn't work:
class RefBuilder<R : Any>(val path: String = "", val next: KClass<R>) {
companion object {
inline fun <T, reified R : Any> from(start: KProperty1<T, R>): RefBuilder<R> {
return RefBuilder(start.name, R::class)
}
}
inline fun <reified N : Any> add(nextRef: (KClass<R>) -> KProperty1<R,N>): RefBuilder<N> {
return RefBuilder("$path.${nextRef.invoke(this.next).name}", N::class)
}
override fun toString() = path
}
fun main() {
val builder = RefBuilder.from(A::propB)
builder.add { it::propC } // this doesn't work
println(builder) // should print: "propB.propC"
}
I would be grateful for any help. Maybe there's even a way more simple solution that I've missed.