How to get a name of member property from the parent object

40 views Asked by At

I want to implement getMemberName function via reflection

data class Inner(val prop: String)
data class Source(
    val member: String,
    val innerMember: Inner
)
fun getMemberName(source: Any, member: Any) : String {
    return "..."
}
fun main() {
  val demo = Source("asd", Inner("asd2"))
  val memberName = getMemberName(demo, demo.member)
  //result: 'member'

  val innerMemberName = getMemberName(demo, demo.innerMember.prop)
  //result: 'innerMember.prop'
}

Maybe somewere in reflection libs exist any common solution?

2

There are 2 answers

0
Nikita Chegodaev On BEST ANSWER

Here is my solution

fun getMemberName(source: Any, member: Any, prefix: String = "") : String {
    val res = source::class.declaredMemberProperties.firstOrNull {
        it.getter.call(source) === member
    }?.name
    if(res != null) {
        return prefix + res
    }
    source::class.declaredMemberProperties.filter {
        !it.getter.call(source)!!.javaClass.kotlin.qualifiedName!!.startsWith("kotlin.")
    }.forEach {
        val res = getMemberName(it.getter.call(source)!!, member, prefix + it.name + ".")
        if(res.isNotEmpty()) {
            return prefix + res
        }
    }
    return ""
}
1
AndrewL On

This may be what you want, but I don't think you can find out the "path" from Source down to the second field in one go, because the field is dereferenced from where it is in the object hierarchy

class Inner {
    val prop = "x"
}
class Source {
    val member = "y"
    val innerMember = Inner()
}
fun getMemberName(source: Any, member: KProperty0<Any>) : String {
    return "${member.name} declared in ${member.javaField?.declaringClass?.name} has value ${member.get()}"
}

fun main() {
    val demo = Source()
    val memberName = getMemberName(demo, demo::member)
    println(memberName) // prints: member declared in Source has value y

    val innerMemberName = getMemberName(demo, demo.innerMember::prop)
    println(innerMemberName) // prints: prop declared in Inner has value x
}

if you want to build a the path from source down N levels deep to a field, that'll be harder as you have devise someway to pass down the property references. A "Bean Accessor" approach might be more what you need, something like Apache Commons PropertyUtils