A Kotlin library for reading and modifying binary metadata in Kotlin/JVM compiler-generated files.
—
Core functionality for reading, writing, and transforming Kotlin class metadata from .class files. This system handles different types of Kotlin class metadata including regular classes, file facades, synthetic classes, and multi-file class structures.
The main sealed class for all Kotlin class metadata operations.
/**
* Base sealed class for all Kotlin class metadata types
*/
sealed class KotlinClassMetadata {
/** Encodes metadata to a new Metadata annotation instance */
abstract fun write(): Metadata
/** Metadata version used for this metadata */
abstract val version: JvmMetadataVersion
/** Additional class-level flags */
abstract val flags: Int
}Static functions for reading and transforming metadata from @Metadata annotations with different compatibility modes.
companion object {
/**
* Reads metadata for supported versions only, throws exception for unsupported versions
* @param annotationData The @Metadata annotation data from a .class file
* @return KotlinClassMetadata instance or null if parsing fails
*/
fun readStrict(annotationData: Metadata): KotlinClassMetadata?
/**
* Reads metadata with best-effort compatibility for newer versions
* @param annotationData The @Metadata annotation data from a .class file
* @return KotlinClassMetadata instance or null if parsing fails
*/
fun readLenient(annotationData: Metadata): KotlinClassMetadata?
/**
* Utility method for reading, transforming, and writing metadata in one operation
* @param metadata The original @Metadata annotation
* @param transformer Function to modify the metadata
* @return New @Metadata annotation with transformations applied
*/
fun transform(metadata: Metadata, transformer: (KotlinClassMetadata) -> Unit): Metadata
/** Regular Kotlin class metadata kind */
const val CLASS_KIND: Int = 1
/** File facade metadata kind */
const val FILE_FACADE_KIND: Int = 2
/** Synthetic class metadata kind */
const val SYNTHETIC_CLASS_KIND: Int = 3
/** Multi-file class facade metadata kind */
const val MULTI_FILE_CLASS_FACADE_KIND: Int = 4
/** Multi-file class part metadata kind */
const val MULTI_FILE_CLASS_PART_KIND: Int = 5
}Usage Examples:
import kotlin.metadata.jvm.KotlinClassMetadata
// Strict reading - fails on unsupported versions
val metadata = KotlinClassMetadata.readStrict(classAnnotation)
if (metadata != null) {
when (metadata) {
is KotlinClassMetadata.Class -> {
println("Regular Kotlin class: ${metadata.kmClass.name}")
}
is KotlinClassMetadata.FileFacade -> {
println("File facade with ${metadata.kmPackage.functions.size} functions")
}
}
}
// Lenient reading - best effort for newer versions
val lentientMetadata = KotlinClassMetadata.readLenient(classAnnotation)
// Transform metadata
val newMetadata = KotlinClassMetadata.transform(originalMetadata) { metadata ->
when (metadata) {
is KotlinClassMetadata.Class -> {
// Modify class metadata
metadata.kmClass.functions.forEach { fn ->
// Add custom annotations or modify function metadata
}
}
}
}Different subclasses representing various types of Kotlin class metadata.
/**
* Represents metadata for a regular Kotlin class
* @param kmClass The class metadata structure
* @param version Metadata version
* @param flags Additional class-level flags
*/
class Class(
val kmClass: KmClass,
override val version: JvmMetadataVersion,
override val flags: Int
) : KotlinClassMetadata() {
override fun write(): Metadata
}
/**
* Represents metadata for top-level declarations (file facades)
* @param kmPackage The package metadata containing top-level declarations
* @param version Metadata version
* @param flags Additional class-level flags
*/
class FileFacade(
val kmPackage: KmPackage,
override val version: JvmMetadataVersion,
override val flags: Int
) : KotlinClassMetadata() {
override fun write(): Metadata
}
/**
* Represents metadata for synthetic classes (lambdas, SAM wrappers, etc.)
* @param kmLambda The lambda metadata (null for non-lambda synthetic classes)
* @param version Metadata version
* @param flags Additional class-level flags
*/
class SyntheticClass(
val kmLambda: KmLambda?,
override val version: JvmMetadataVersion,
override val flags: Int
) : KotlinClassMetadata() {
override fun write(): Metadata
}
/**
* Represents metadata for multi-file class facades
* @param partClassNames List of class names that are parts of this facade
* @param version Metadata version
* @param flags Additional class-level flags
*/
class MultiFileClassFacade(
val partClassNames: List<String>,
override val version: JvmMetadataVersion,
override val flags: Int
) : KotlinClassMetadata() {
override fun write(): Metadata
}
/**
* Represents metadata for multi-file class parts
* @param kmPackage The package metadata for this part
* @param facadeClassName The name of the facade class this part belongs to
* @param version Metadata version
* @param flags Additional class-level flags
*/
class MultiFileClassPart(
val kmPackage: KmPackage,
val facadeClassName: String,
override val version: JvmMetadataVersion,
override val flags: Int
) : KotlinClassMetadata() {
override fun write(): Metadata
}
/**
* Represents metadata for unsupported class files
* @param version Metadata version
* @param flags Additional class-level flags
*/
class Unknown(
override val version: JvmMetadataVersion,
override val flags: Int
) : KotlinClassMetadata() {
override fun write(): Metadata
}Usage Examples:
// Working with different metadata types
when (metadata) {
is KotlinClassMetadata.Class -> {
val klass = metadata.kmClass
println("Class name: ${klass.name}")
println("Functions: ${klass.functions.map { it.name }}")
println("Properties: ${klass.properties.map { it.name }}")
// Access constructors
klass.constructors.forEach { constructor ->
println("Constructor with ${constructor.valueParameters.size} parameters")
}
}
is KotlinClassMetadata.FileFacade -> {
val pkg = metadata.kmPackage
println("Top-level functions:")
pkg.functions.forEach { function ->
println(" ${function.name}: ${function.returnType}")
}
println("Top-level properties:")
pkg.properties.forEach { property ->
println(" ${property.name}: ${property.returnType}")
}
}
is KotlinClassMetadata.SyntheticClass -> {
val lambda = metadata.kmLambda
if (lambda != null) {
println("Lambda function: ${lambda.function}")
}
}
is KotlinClassMetadata.MultiFileClassFacade -> {
println("Multi-file facade with parts: ${metadata.partClassNames}")
}
is KotlinClassMetadata.MultiFileClassPart -> {
println("Multi-file part of facade: ${metadata.facadeClassName}")
println("Contains ${metadata.kmPackage.functions.size} functions")
}
is KotlinClassMetadata.Unknown -> {
println("Unknown or unsupported metadata format")
}
}The metadata reading functions return null when parsing fails or the metadata format is unsupported. The readStrict function is more restrictive and may throw exceptions for incompatible versions, while readLenient attempts best-effort parsing.
Always check for null return values and handle the Unknown metadata type for robust metadata processing.
Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-metadata-jvm