How to get the relative class name of data classes

Viewed 141

Suppose we have a structure like this:

data class MyClass(
  val inner: MyInnerClass
) {
  data class MyInnerClass(
    val foo: String
  )
}

How can I get the relative class name MyClass.MyInnerClass? I already have a KType of that class. And if I look at this with the debugger I can find the name:

screenshot of intellij debugger

I could not find out how to access this with code.

1 Answers

This is possible using the kotlin-reflect artifact as a dependency. https://kotlinlang.org/docs/reflection.html#jvm-dependency

In my Maven project I add a new dependency:

<dependencies>
  <dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-reflect</artifactId>
    <version>1.7.0</version>
  </dependency>
</dependencies>

I didn't use Gradle for this, but I think you'd use

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-reflect:1.7.0")
}

to include it.

I made a data class similar to yours in a package named innerclass:

package innerclass

data class MyClass(
    val inner: MyInnerClass
) {
    data class MyInnerClass(val foo:String)
    data class AnotherInnerClass(val bar:String)
}

Then my Main.kt looks like this:

import innerclass.MyClass
import kotlin.reflect.KClass

fun main(args: Array<String>) {
    println("Using class type as reference: ${MyClass::class.qualifiedName}")
    printRelativeClassNames(MyClass::class.nestedClasses)

    val test = MyClass(MyClass.MyInnerClass("foo"))
    println("\nUsing instance as reference: ${test::class.qualifiedName}")
    printRelativeClassNames(test::class.nestedClasses)
}

private val KClass<*>.packageFqName: String?
    get() {
        return java.`package`.name
    }

private val KClass<*>.relativeClassName: String?
    get() {
        return qualifiedName?.removePrefix("${packageFqName}.")
    }

fun printRelativeClassNames(nestedClasses: Collection<KClass<*>>) {
    nestedClasses.forEach {
        println("Actual Kotlin class: $it")
        println(it.relativeClassName)
    }
}

When I run the program, it outputs:

Using class type as reference: innerclass.MyClass
Actual Kotlin class: class innerclass.MyClass$AnotherInnerClass
MyClass.AnotherInnerClass
Actual Kotlin class: class innerclass.MyClass$MyInnerClass
MyClass.MyInnerClass

Using instance as reference: innerclass.MyClass
Actual Kotlin class: class innerclass.MyClass$AnotherInnerClass
MyClass.AnotherInnerClass
Actual Kotlin class: class innerclass.MyClass$MyInnerClass
MyClass.MyInnerClass

Using reflection (and a little string manipulation) I can get the Kotlin class as well as print out the relative name of the class.

Let me know if you hit any issues.

Related