Я хочу определить, является ли класс JVM классом Котлина или нет

Я хочу сделать особую функциональность, если столкнусь с классом Kotlin по сравнению с общим классом Java. Как я могу определить, является ли это класс Kotlin?

Я надеялся, что вызов someClass.kotlin бросил бы исключение или потерпел бы неудачу, если бы класс не был Kotlin. Но это просто оборачивает классы Java. Тогда я заметил, что если я делаю someClass.kotlin.primaryConstructor это кажется null для всех классов Java, даже если у них есть конструктор по умолчанию, это хороший маркер? Но может ли это вернуться null для класса Kotlin также?

Как лучше всего сказать "это класс Kotlin?"

2 ответа

Решение

Kotlin добавляет аннотацию ко всем своим классам, и вы можете смело проверять его существование по имени. Это деталь реализации, которая со временем может измениться, но некоторые ключевые библиотеки используют эту аннотацию, так что, вероятно, она будет работать бесконечно долго.

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

Может использоваться как:

someClass.isKotlinClass()

Класс kotlin.Metadata не доступен напрямую, потому что он помечен internal во время выполнения Kotlin.

Хотя другой ответ может работать (возможно, устаревший), многие функции отражения не будут работать с классами файлов или сгенерированными классами (лямбда-выражениями и т. д.).

Однако в аннотации @Metadata есть параметр, который может сказать вам, является ли класс тем, что вы ищете:

Тип метаданных, которые кодирует эта аннотация. Компилятор Kotlin распознает следующие типы (см. KotlinClassHeader.Kind):

1 Класс
2 Файл
3 Синтетический класс
4 Фасад многофайлового класса
5 Часть многофайлового класса

Файл класса с типом, не указанным здесь, рассматривается как файл, отличный от Kotlin.

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

Мы можем воспользоваться этим, чтобы убедиться, что мы получаем только настоящие классы:

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

Я могу подтвердить, что это работает в 1.6.20.

Другие вопросы по тегам