Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
150 lines (110 sloc) 6.64 KB


This library provides an API to read and modify metadata of binary files generated by the Kotlin/JVM compiler, namely .class and .kotlin_module files.


To use this library in your project, add a dependency on org.jetbrains.kotlinx:kotlinx-metadata-jvm:$kotlinx_metadata_version (where kotlinx_metadata_version is the version of the library).

Example usage in Maven:


Example usage in Gradle:

repositories {

dependencies {
    compile "org.jetbrains.kotlinx:kotlinx-metadata-jvm:$kotlinx_metadata_version"


The entry point for reading the Kotlin metadata of a .class file is The data it takes is encapsulated in KotlinClassHeader which is basically what is written in the kotlin.Metadata annotation on the class file generated by the Kotlin compiler. Construct KotlinClassHeader by reading the values from kotlin.Metadata reflectively or from some other resource, and then use to obtain the correct instance of the class metadata.

val header = KotlinClassHeader(
    /* pass Metadata.k, Metadata.d1, Metadata.d2, etc as arguments ... */
val metadata =

KotlinClassMetadata is a sealed class, with subclasses representing all the different kinds of classes generated by the Kotlin compiler. Unless you're sure that you're reading a class of a specific kind and can do a simple cast, a when is a good choice to handle all the possibilities:

when (metadata) {
    is KotlinClassMetadata.Class -> ...
    is KotlinClassMetadata.FileFacade -> ...
    is KotlinClassMetadata.SyntheticClass -> ...
    is KotlinClassMetadata.MultiFileClassFacade -> ...
    is KotlinClassMetadata.MultiFileClassPart -> ...
    is KotlinClassMetadata.Unknown -> ...

Let's assume we've obtained an instance of KotlinClassMetadata.Class; other kinds of classes are handled similarly, except some of them have metadata in a slightly different form. The main way to make sense of the underlying metadata is to invoke toKmClass, which returns an instance of KmClass (Km is a shorthand for “Kotlin metadata”):

val klass = metadata.toKmClass()
println( { })
println( { })

Please refer to MetadataSmokeTest.listInlineFunctions for an example where all inline functions are read from the class metadata along with their JVM signatures.


Numerous objects have a property named flags of type Flags. These flags represent modifiers or other boolean attributes of a declaration or a type. To check if a certain flag is present, call one of the flags in Flag on the given integer value. The set of applicable flags is documented on each property or the corresponding visit* method. For example, for functions, this is common declaration flags (visibility, modality) plus Flag.Function flags:

val function: KmFunction = ...
if (Flag.IS_PUBLIC(function.flags)) {
    println("function ${} is public")
if (Flag.Function.IS_SUSPEND(function.flags)) {
    println("function ${} has the 'suspend' modifier")

Writing metadata

To create metadata of a Kotlin class file from scratch, construct an instance of KmClass/KmPackage/KmLambda, fill it with the data and call accept with the Writer class declared in the corresponding KotlinClassMetadata subclass. Finally, use KotlinClassMetadata.header to obtain the raw data and write it to the kotlin.Metadata annotation on a class file.

When using metadata writers from Kotlin source code, it's very convenient to use Kotlin scoping functions such as apply to reduce boilerplate:

// Writing metadata of a class
val klass = KmClass().apply {
    // Setting the name and the modifiers of the class.
    // Flags are constructed by invoking "flagsOf(...)"
    name = "MyClass"
    flags = flagsOf(Flag.IS_PUBLIC)

    // Adding one public primary constructor
    constructors += KmConstructor(flagsOf(Flag.IS_PUBLIC, Flag.Constructor.IS_PRIMARY)).apply {
        // Setting the JVM signature (for example, to be used by kotlin-reflect)
        signature = JvmMethodSignature("<init>", "()V")


// Finally writing everything to arrays of bytes
val header = KotlinClassMetadata.Class.Writer().apply(klass::accept).write().header

// Use header.kind, header.data1, header.data2, etc. to write values to kotlin.Metadata

Please refer to MetadataSmokeTest.produceKotlinClassFile for an example where metadata of a simple Kotlin class is created, and then the class file is produced with ASM and loaded by Kotlin reflection.

Module metadata

Similarly to how KotlinClassMetadata is used to read/write metadata of Kotlin .class files, KotlinModuleMetadata is the entry point for reading/writing .kotlin_module files. Use or KotlinModuleMetadata.Writer in very much the same fashion as with the class files. The only difference is that the source for the reader (and the result of the writer) is a simple byte array, not the structured data loaded from kotlin.Metadata:

// Read the module metadata
val bytes = File("META-INF/main.kotlin_module").readBytes()
val metadata =
val module = metadata.toKmModule()

// Write the module metadata
val bytes = KotlinModuleMetadata.Writer().apply(module::accept).write().bytes


Note that until you load the actual underlying data of a KotlinClassMetadata or KotlinModuleMetadata instance by invoking accept or one of the toKm... methods, the data is not completely parsed and verified. If you need to check if the data is not horribly corrupted before proceeding, ensure that either of those is called:

val metadata: KotlinClassMetadata.Class = ...

try {
    // Guarantees eager parsing of the underlying data
} catch (e: Exception) {
    System.err.println("Metadata is corrupted!")
You can’t perform that action at this time.