インスタンスがkotlinかどうかを判定する

インスタンスがkotlinかどうかを判定する方法が知りたかったので調べてみました。

下記バージョンで試してみます。

  • kotlin 1.4.21

Model

下記のようなModelをjavaとkotlinで定義します。

JavaModel.java

public class JavaModel {
}

KotlinModel.kt

class KotlinModel {
}

Metadataで確認

下記の様に、isKotlinClass()という拡張関数を定義します。
Class.getDeclaredAnnotation()でクラスに定義されているアノテーションを取得して、
Metadataがある場合kotlinクラスになります。

fun Class<*>.isKotlinClass(): Boolean {
    return this.getDeclaredAnnotation(Metadata::class.java) != null
}

確認してみます。
::class.javaでClassクラスのインスタンスを取得して、isKotlinClass()の結果を出力してみます。

fun main() {
    val kotlinModel = KotlinModel()
    val javaModel = JavaModel()

    println("kotlinModel: ${kotlinModel::class.java.isKotlinClass()}")
    println("javaModel: ${javaModel::class.java.isKotlinClass()}")
}

実行すると判定出来ました。

kotlinModel: true
javaModel: false

@Metadataが何かを確認するために、KotlinModel.ktをdecompileしてみます。
下記のように@Metadataが付与されています。
kotlinのドキュメントを確認してみると、@Metadataはkotlinコンパイラによって生成されたクラスに付与されるようです。
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-metadata/

@Metadata(
   mv = {1, 4, 1},
   bv = {1, 0, 3},
   k = 1,
   d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0003"},
   d2 = {"Lcom/example/kotlin/model/KotlinModel;", "", "()V", "detect-kotlin-class.main"}
)
public final class KotlinModel {
}

KClassでも下記のように判定出来るかと思いましたが、
KClassの場合、kotlin reflection API@Metadataを取得出来ないので無理でした。

fun KClass<*>.isKotlinClass(): Boolean {
    return this.annotations.any {
        it.annotationClass == Metadata::class
    }
}

同様に確認してみます。

fun main() {
    val kotlinModel = KotlinModel()
    val javaModel = JavaModel()

    // Can't find from KClass.annotation
    println("kotlinModel: ${kotlinModel::class.isKotlinClass()}")
    println("javaModel: ${javaModel::class.isKotlinClass()}")
}

下記のように両方falseになってしまいます。

kotlinModel: false
javaModel: false

 

sample codeは下記にあげました。
github.com

 

おわり。
 
 

[参考]
https://github.com/spring-projects/spring-framework/pull/1060/files#diff-244315b45582a5b7573a15644b16c373R48
https://stackoverflow.com/questions/39806721/i-want-to-detect-if-a-jvm-class-is-a-kotlin-class-or-not