New kotlinx-metadata-jvm release
Update changelog for kotlinx-metadata-jvm 0.6.0, add migration guide, and actualize ReadMe.md Document releasing process Co-authored-by: Alexander Udalov <Alexander.Udalov@jetbrains.com> Merge-request: KT-MR-8206 Merged-by: Leonid Startsev <leonid.startsev@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
2dc13506f5
commit
d646906437
@@ -35,17 +35,20 @@ dependencies {
|
||||
|
||||
## Overview
|
||||
|
||||
The entry point for reading the Kotlin metadata of a `.class` file is [`KotlinClassMetadata.read`](src/kotlinx/metadata/jvm/KotlinClassMetadata.kt). The data it takes is encapsulated in [`KotlinClassHeader`](src/kotlinx/metadata/jvm/KotlinClassHeader.kt) which is basically what is written in the [`kotlin.Metadata`](../../stdlib/jvm/runtime/kotlin/Metadata.kt) 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 `KotlinClassMetadata.read` to obtain the correct instance of the class metadata.
|
||||
The entry point for reading the Kotlin metadata of a `.class` file is [`KotlinClassMetadata.read`](src/kotlinx/metadata/jvm/KotlinClassMetadata.kt).
|
||||
The data it takes is the [`kotlin.Metadata`](../../stdlib/jvm/runtime/kotlin/Metadata.kt) annotation on the class file generated by the Kotlin compiler.
|
||||
Obtain the `kotlin.Metadata` annotation reflectively or construct it from binary representation (e.g. by reading classfile with `org.objectweb.asm.ClassReader`),
|
||||
and then use `KotlinClassMetadata.read` to obtain the correct instance of the class metadata.
|
||||
|
||||
```kotlin
|
||||
val header = KotlinClassHeader(
|
||||
...
|
||||
/* pass Metadata.k, Metadata.d1, Metadata.d2, etc as arguments ... */
|
||||
val metadataAnnotation = Metadata(
|
||||
// pass arguments here
|
||||
)
|
||||
val metadata = KotlinClassMetadata.read(header)
|
||||
val metadata = KotlinClassMetadata.read(metadataAnnotation)
|
||||
```
|
||||
|
||||
`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:
|
||||
`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:
|
||||
|
||||
```kotlin
|
||||
when (metadata) {
|
||||
@@ -58,7 +61,8 @@ when (metadata) {
|
||||
}
|
||||
```
|
||||
|
||||
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”):
|
||||
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”):
|
||||
|
||||
```kotlin
|
||||
val klass = metadata.toKmClass()
|
||||
@@ -70,7 +74,10 @@ Please refer to [`MetadataSmokeTest.listInlineFunctions`](test/kotlinx/metadata/
|
||||
|
||||
## Flags
|
||||
|
||||
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`](../src/kotlinx/metadata/Flag.kt) 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:
|
||||
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`](../src/kotlinx/metadata/Flag.kt) on the given integer value.
|
||||
The set of applicable flags is documented for each Node property which has type `Flags`.
|
||||
For example, functions have common declaration flags (visibility, modality) plus `Flag.Function` flags:
|
||||
|
||||
```kotlin
|
||||
val function: KmFunction = ...
|
||||
@@ -84,7 +91,8 @@ if (Flag.Function.IS_SUSPEND(function.flags)) {
|
||||
|
||||
## 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.
|
||||
To create metadata of a Kotlin class file from scratch, construct an instance of `KmClass`/`KmPackage`/`KmLambda`, fill it with the data and call corresponding `KotlinClassMetadata.write` function.
|
||||
Resulting `KotlinClassMetadata.annotationData` can be used to write `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:
|
||||
|
||||
@@ -105,18 +113,19 @@ val klass = KmClass().apply {
|
||||
...
|
||||
}
|
||||
|
||||
// Finally writing everything to arrays of bytes
|
||||
val header = KotlinClassMetadata.Class.Writer().apply(klass::accept).write().header
|
||||
val annotation = KotlinClassMetadata.writeClass(klass).annotationData
|
||||
|
||||
// Use header.kind, header.data1, header.data2, etc. to write values to kotlin.Metadata
|
||||
...
|
||||
// Write annotation directly or use annotation.kind, annotation.data1, annotation.data2, etc.
|
||||
```
|
||||
|
||||
Please refer to [`MetadataSmokeTest.produceKotlinClassFile`](test/kotlinx/metadata/test/MetadataSmokeTest.kt) 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.
|
||||
Please refer to [`MetadataSmokeTest.produceKotlinClassFile`](test/kotlinx/metadata/test/MetadataSmokeTest.kt) 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`](src/kotlinx/metadata/jvm/KotlinModuleMetadata.kt) is the entry point for reading/writing `.kotlin_module` files. Use `KotlinModuleMetadata.read` 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`:
|
||||
Similarly to how `KotlinClassMetadata` is used to read/write metadata of Kotlin `.class` files, [`KotlinModuleMetadata`](src/kotlinx/metadata/jvm/KotlinModuleMetadata.kt)
|
||||
is the entry point for reading/writing `.kotlin_module` files. Use `KotlinModuleMetadata.read` or `KotlinModuleMetadata.write` 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`:
|
||||
|
||||
```kotlin
|
||||
// Read the module metadata
|
||||
@@ -126,13 +135,14 @@ val module = metadata.toKmModule()
|
||||
...
|
||||
|
||||
// Write the module metadata
|
||||
val bytes = KotlinModuleMetadata.Writer().apply(module::accept).write().bytes
|
||||
val bytes = KotlinModuleMetadata.write(module).bytes
|
||||
File("META-INF/main.kotlin_module").writeBytes(bytes)
|
||||
```
|
||||
|
||||
## Laziness
|
||||
|
||||
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:
|
||||
Note that until you load the actual underlying data of a `KotlinClassMetadata` or `KotlinModuleMetadata` instance by invoking 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:
|
||||
|
||||
```kotlin
|
||||
val metadata: KotlinClassMetadata.Class = ...
|
||||
|
||||
Reference in New Issue
Block a user