18

I want to do special functionality if I encounter a Kotlin class as compared to a generic Java class. How can I detect if it is a Kotlin class?

I was hoping that calling someClass.kotlin would throw an exception or fail if the class wasn't Kotlin. But it wraps Java classes just fine. Then I noticed that if I do someClass.kotlin.primaryConstructor it seems to be null for all java classes even if they have a default constructor, is that a good marker? But can that return null for a Kotlin class as well?

What is the best way to say "is this a Kotlin class?"

2 Answers 2

20

Kotlin adds an annotation to all of its classes, and you can safely check for its existence by name. This is an implementation detail and could change over time, but some key libraries use this annotation so it is likely to be ok indefinitely.

fun Class<*>.isKotlinClass(): Boolean {
    return this.declaredAnnotations.any {
        it.annotationClass.qualifiedName == "kotlin.Metadata"
    }
}

Can be used as:

someClass.isKotlinClass()

The class kotlin.Metadata is not accessed directly because it is marked internal in the Kotlin runtime.

Sign up to request clarification or add additional context in comments.

5 Comments

Why not compare the class directly? it.annotationClass == Metadata::class
The class is not accessible, is internal
Ah. It seems to be accessible from Java. For example, I wrote this (unmerged) pull request for the Spring Framework: github.com/spring-projects/spring-framework/pull/1060/… (yes, they wanted it written in Java, eek).
Yep, Java doesn't respect the Kotlin idea of internal
Metadata is internal in Kotlin 1.2 but it is public in Kotlin 1.3
1

While the other answer may work (possibly outdated), many reflection features will not work on file classes or generated classes (lambdas, etc).

However, there is a parameter in the @Metadata annotation that can tell you if the class is what you are looking for:

A kind of the metadata this annotation encodes. Kotlin compiler recognizes the following kinds (see KotlinClassHeader.Kind):

1 Class
2 File
3 Synthetic class
4 Multi-file class facade
5 Multi-file class part

The class file with a kind not listed here is treated as a non-Kotlin file.

@get:JvmName("k")
val kind: Int = 1

We can take advantage of this to make sure we are only getting real classes:

val Class<*>.isKotlinClass get() = getAnnotation(Metadata::class.java)?.kind == 1

I can confirm this works in 1.6.20

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.