Use Metadata directly instead of KotlinClassHeader; rewrite latter to Java

so Java clients can obtain Metadata instance from it.
This commit is contained in:
Leonid Startsev
2022-04-21 15:26:05 +03:00
committed by Space Team
parent 471882b743
commit 3d679b76bc
10 changed files with 347 additions and 260 deletions
@@ -231,35 +231,36 @@ public final class kotlinx/metadata/jvm/KmPackageParts {
public final fun getMultiFileClassParts ()Ljava/util/Map;
}
public final class kotlinx/metadata/jvm/KotlinClassHeader {
public final class kotlinx/metadata/jvm/KotlinClassHeader : kotlin/Metadata {
public static final field CLASS_KIND I
public static final field COMPATIBLE_BYTECODE_VERSION [I
public static final field COMPATIBLE_METADATA_VERSION [I
public static final field Companion Lkotlinx/metadata/jvm/KotlinClassHeader$Companion;
public static final field FILE_FACADE_KIND I
public static final field MULTI_FILE_CLASS_FACADE_KIND I
public static final field MULTI_FILE_CLASS_PART_KIND I
public static final field SYNTHETIC_CLASS_KIND I
public fun <init> (Ljava/lang/Integer;[I[I[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V
public fun <init> (Ljava/lang/Integer;[I[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V
public final fun getBytecodeVersion ()[I
public final fun getData1 ()[Ljava/lang/String;
public final fun getData2 ()[Ljava/lang/String;
public final fun getExtraInt ()I
public final fun getExtraString ()Ljava/lang/String;
public final fun getKind ()I
public final fun getMetadataVersion ()[I
public final fun getPackageName ()Ljava/lang/String;
}
public final class kotlinx/metadata/jvm/KotlinClassHeader$Companion {
public fun annotationType ()Ljava/lang/Class;
public fun bv ()[I
public fun d1 ()[Ljava/lang/String;
public fun d2 ()[Ljava/lang/String;
public fun k ()I
public fun mv ()[I
public fun pn ()Ljava/lang/String;
public fun xi ()I
public fun xs ()Ljava/lang/String;
}
public abstract class kotlinx/metadata/jvm/KotlinClassMetadata {
public static final field CLASS_KIND I
public static final field COMPATIBLE_METADATA_VERSION [I
public static final field Companion Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;
public synthetic fun <init> (Lkotlinx/metadata/jvm/KotlinClassHeader;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getHeader ()Lkotlinx/metadata/jvm/KotlinClassHeader;
public static final fun read (Lkotlinx/metadata/jvm/KotlinClassHeader;)Lkotlinx/metadata/jvm/KotlinClassMetadata;
public static final field FILE_FACADE_KIND I
public static final field MULTI_FILE_CLASS_FACADE_KIND I
public static final field MULTI_FILE_CLASS_PART_KIND I
public static final field SYNTHETIC_CLASS_KIND I
public synthetic fun <init> (Lkotlin/Metadata;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getHeader ()Lkotlin/Metadata;
public static final fun read (Lkotlin/Metadata;)Lkotlinx/metadata/jvm/KotlinClassMetadata;
}
public final class kotlinx/metadata/jvm/KotlinClassMetadata$Class : kotlinx/metadata/jvm/KotlinClassMetadata {
@@ -276,7 +277,7 @@ public final class kotlinx/metadata/jvm/KotlinClassMetadata$Class$Writer : kotli
}
public final class kotlinx/metadata/jvm/KotlinClassMetadata$Companion {
public final fun read (Lkotlinx/metadata/jvm/KotlinClassHeader;)Lkotlinx/metadata/jvm/KotlinClassMetadata;
public final fun read (Lkotlin/Metadata;)Lkotlinx/metadata/jvm/KotlinClassMetadata;
public final fun writeClass (Lkotlinx/metadata/KmClass;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$Class;
public static synthetic fun writeClass$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Lkotlinx/metadata/KmClass;[IIILjava/lang/Object;)Lkotlinx/metadata/jvm/KotlinClassMetadata$Class;
public final fun writeFileFacade (Lkotlinx/metadata/KmPackage;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$FileFacade;
@@ -23,6 +23,10 @@ group = "org.jetbrains.kotlinx"
val deployVersion = findProperty("kotlinxMetadataDeployVersion") as String?
version = deployVersion ?: "0.1-SNAPSHOT"
//kotlin {
// explicitApiWarning()
//}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
@@ -0,0 +1,173 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.jvm;
import kotlin.DeprecationLevel;
import kotlin.Metadata;
import kotlin.ReplaceWith;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion;
import java.lang.annotation.Annotation;
import java.util.Arrays;
/**
* An implementation of the {@link Metadata} annotation on a JVM class file, containing the metadata of Kotlin declarations declared in the class file.
* This class is intended to be used by Java clients to be able to pass a {@link Metadata} instance to various methods in the library if it cannot be obtained via reflection.
* Kotlin clients should be able to instantiate annotation directly and therefore should not use this class.
*/
@SuppressWarnings("ClassExplicitlyAnnotation")
@kotlin.Deprecated(message = "Kotlin clients should instantiate Metadata annotation directly", replaceWith = @ReplaceWith(expression = "Metadata", imports = {}), level = DeprecationLevel.ERROR)
public final class KotlinClassHeader implements Metadata {
private final int k;
@NotNull private final int[] mv;
@NotNull private final String[] d1;
@NotNull private final String[] d2;
@NotNull private final String xs;
@NotNull private final String pn;
private final int xi;
/**
* @param kind see {@link Metadata#k()}
* @param metadataVersion see {@link Metadata#mv()}
* @param data1 see {@link Metadata#d1()}
* @param data2 see {@link Metadata#d2()}
* @param extraString see {@link Metadata#xs()}
* @param packageName see {@link Metadata#pn()}
* @param extraInt see {@link Metadata#xi()}
*/
@SuppressWarnings("SSBasedInspection")
public KotlinClassHeader(
@Nullable Integer kind,
@Nullable int[] metadataVersion,
@Nullable String[] data1,
@Nullable String[] data2,
@Nullable String extraString,
@Nullable String packageName,
@Nullable Integer extraInt
) {
if (kind != null) this.k = kind; else this.k = 1;
if (metadataVersion != null) this.mv = metadataVersion; else this.mv = new int[0];
if (data1 != null) this.d1 = data1; else this.d1 = new String[0];
if (data2 != null) this.d2 = data2; else this.d2 = new String[0];
if (extraString != null) this.xs = extraString; else this.xs = "";
if (packageName != null) this.pn = packageName; else this.pn = "";
if (extraInt != null) this.xi = extraInt; else this.xi = 0;
}
/**
* {@inheritdoc}
*/
@Override
public int k() {
return k;
}
/**
* {@inheritdoc}
*/
@Override
public int[] mv() {
return mv;
}
/**
* {@inheritdoc}
*/
@Override
@Deprecated
public int[] bv() {
return new int[] {1, 0, 3};
}
/**
* {@inheritdoc}
*/
@Override
public String[] d1() {
return d1;
}
/**
* {@inheritdoc}
*/
@Override
public String[] d2() {
return d2;
}
/**
* {@inheritdoc}
*/
@Override
public String xs() {
return xs;
}
/**
* {@inheritdoc}
*/
@Override
public String pn() {
return pn;
}
/**
* {@inheritdoc}
*/
@Override
public int xi() {
return xi;
}
/**
* {@inheritdoc}
*/
@Override
public Class<? extends Annotation> annotationType() {
return Metadata.class;
}
// TODO: equals, hashCode, etc as in Java Annotation contract?
/**
* Use {@link KotlinClassMetadata#CLASS_KIND} instead
*/
@Deprecated
public static final int CLASS_KIND = 1;
/**
* Use {@link KotlinClassMetadata#FILE_FACADE_KIND} instead
*/
@Deprecated
public static final int FILE_FACADE_KIND = 2;
/**
* Use {@link KotlinClassMetadata#SYNTHETIC_CLASS_KIND} instead
*/
@Deprecated
public static final int SYNTHETIC_CLASS_KIND = 3;
/**
* Use {@link KotlinClassMetadata#MULTI_FILE_CLASS_FACADE_KIND} instead
*/
@Deprecated
public static final int MULTI_FILE_CLASS_FACADE_KIND = 4;
/**
* Use {@link KotlinClassMetadata#MULTI_FILE_CLASS_PART_KIND} instead
*/
@Deprecated
public static final int MULTI_FILE_CLASS_PART_KIND = 5;
/**
* Use {@link KotlinClassMetadata#COMPATIBLE_METADATA_VERSION} instead
*/
@Deprecated
public static final int[] COMPATIBLE_METADATA_VERSION = Arrays.copyOf(JvmMetadataVersion.INSTANCE.toArray(), 3);
}
@@ -1,179 +0,0 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
package kotlinx.metadata.jvm
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
/**
* A mirror to the [Metadata] annotation on a JVM class file, containing the metadata of Kotlin declarations declared in the class file.
* Properties of this class correspond 1:1 to the properties of [Metadata].
*
* @param kind see [kind]
* @param metadataVersion see [metadataVersion]
* @param bytecodeVersion see [bytecodeVersion]
* @param data1 see [data1]
* @param data2 see [data2]
* @param extraString see [extraString]
* @param packageName see [packageName]
* @param extraInt see [extraInt]
*/
class KotlinClassHeader
@Deprecated(
"Use another constructor, which doesn't take bytecodeVersion as a parameter.",
ReplaceWith("KotlinClassHeader(kind, metadataVersion, data1, data2, extraString, packageName, extraInt)"),
DeprecationLevel.ERROR
)
constructor(
kind: Int?,
metadataVersion: IntArray?,
bytecodeVersion: IntArray?,
data1: Array<String>?,
data2: Array<String>?,
extraString: String?,
packageName: String?,
extraInt: Int?
) {
@Suppress("DEPRECATION_ERROR")
constructor(
kind: Int?,
metadataVersion: IntArray?,
data1: Array<String>?,
data2: Array<String>?,
extraString: String?,
packageName: String?,
extraInt: Int?
) : this(kind, metadataVersion, null, data1, data2, extraString, packageName, extraInt)
/**
* A kind of the metadata this header encodes.
*
* @see Metadata.kind
* @see CLASS_KIND
* @see FILE_FACADE_KIND
* @see SYNTHETIC_CLASS_KIND
* @see MULTI_FILE_CLASS_FACADE_KIND
* @see MULTI_FILE_CLASS_PART_KIND
*/
val kind: Int = kind ?: 1
/**
* The version of the metadata provided in other properties of this header.
*
* @see Metadata.metadataVersion
* @see COMPATIBLE_METADATA_VERSION
*/
val metadataVersion: IntArray = metadataVersion ?: intArrayOf()
/**
* The version of the bytecode interface (naming conventions, signatures) of the corresponding class file.
*
* @see Metadata.bytecodeVersion
* @see COMPATIBLE_BYTECODE_VERSION
*/
@Deprecated(
"Bytecode version had no significant use in Kotlin metadata and it will be removed in a future version.",
level = DeprecationLevel.ERROR
)
val bytecodeVersion: IntArray = bytecodeVersion ?: intArrayOf()
/**
* The first array of strings used to encode the metadata.
*
* @see Metadata.data1
*/
val data1: Array<String> = data1 ?: emptyArray()
/**
* The second array of strings used to encode the metadata.
*
* @see Metadata.data2
*/
val data2: Array<String> = data2 ?: emptyArray()
/**
* An extra string field for the metadata.
*
* @see Metadata.extraString
*/
val extraString: String = extraString ?: ""
/**
* Fully qualified name of the Kotlin package of the corresponding class, in case [JvmPackageName] was used.
*
* @see Metadata.packageName
*/
val packageName: String = packageName ?: ""
/**
* An extra int field for the metadata.
*
* @see Metadata.extraInt
*/
val extraInt: Int = extraInt ?: 0
companion object {
/**
* A class file kind signifying that the corresponding class file contains a declaration of a Kotlin class.
*
* @see kind
*/
const val CLASS_KIND = 1
/**
* A class file kind signifying that the corresponding class file is a compiled Kotlin file facade.
*
* @see kind
*/
const val FILE_FACADE_KIND = 2
/**
* A class file kind signifying that the corresponding class file is synthetic, e.g. it's a class for lambda, `$DefaultImpls` class
* for interface method implementations, `$WhenMappings` class for optimized `when` over enums, etc.
*
* @see kind
*/
const val SYNTHETIC_CLASS_KIND = 3
/**
* A class file kind signifying that the corresponding class file is a compiled multi-file class facade.
*
* @see kind
* @see JvmMultifileClass
*/
const val MULTI_FILE_CLASS_FACADE_KIND = 4
/**
* A class file kind signifying that the corresponding class file is a compiled multi-file class part, i.e. an internal class
* with method bodies and their metadata, accessed only from the corresponding facade.
*
* @see kind
* @see JvmMultifileClass
*/
const val MULTI_FILE_CLASS_PART_KIND = 5
/**
* The latest metadata version supported by this version of the library.
*
* @see metadataVersion
*/
@JvmField
val COMPATIBLE_METADATA_VERSION = JvmMetadataVersion.INSTANCE.toArray().copyOf()
/**
* The latest bytecode version supported by this version of the library.
*
* @see bytecodeVersion
*/
@Deprecated(
"Bytecode version had no significant use in Kotlin metadata and it will be removed in a future version.",
level = DeprecationLevel.ERROR
)
@JvmField
val COMPATIBLE_BYTECODE_VERSION = intArrayOf(1, 0, 3)
}
}
@@ -14,6 +14,7 @@ import kotlinx.metadata.jvm.impl.writeProtoBufData
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable
import java.util.*
import kotlin.LazyThreadSafetyMode.PUBLICATION
/**
@@ -22,11 +23,11 @@ import kotlin.LazyThreadSafetyMode.PUBLICATION
* To create an instance of [KotlinClassMetadata], first obtain a [KotlinClassHeader] instance by loading the contents
* of the [Metadata] annotation on a class file, and then call [KotlinClassMetadata.read].
*/
sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
sealed class KotlinClassMetadata(val header: Metadata) {
/**
* Represents metadata of a class file containing a declaration of a Kotlin class.
*/
class Class internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header) {
class Class internal constructor(header: Metadata) : KotlinClassMetadata(header) {
private val classData by lazy(PUBLICATION) {
val data1 = (header.data1.takeIf(Array<*>::isNotEmpty)
?: throw InconsistentKotlinMetadataException("data1 must not be empty"))
@@ -54,7 +55,6 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
/**
* A [KmClassVisitor] that generates the metadata of a Kotlin class.
*/
// @Suppress("INVISIBLE_REFERENCE") FIXME: maybe make supertype internal?
@OptIn(DeprecatedVisitor::class)
@Deprecated(
"Writer API is deprecated. Please use KotlinClassMetadata.writeClass(kmClass, metadataVersion, extraInt)",
@@ -65,7 +65,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
* Returns the metadata of the class that was written with this writer.
*
* @param metadataVersion metadata version to be written to the metadata (see [KotlinClassHeader.metadataVersion]),
* [KotlinClassHeader.COMPATIBLE_METADATA_VERSION] by default. Cannot be less (lexicographically) than `[1, 4]`
* [KotlinClassMetadata.COMPATIBLE_METADATA_VERSION] by default. Cannot be less (lexicographically) than `[1, 4]`
* @param extraInt the value of the class-level flags to be written to the metadata (see [KotlinClassHeader.extraInt]),
* 0 by default
*/
@@ -75,12 +75,12 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
level = DeprecationLevel.ERROR
)
fun write(
metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): Class {
checkMetadataVersion(metadataVersion)
val (d1, d2) = writeProtoBufData(t.build(), c)
val metadata = KotlinClassHeader(KotlinClassHeader.CLASS_KIND, metadataVersion, d1, d2, null, null, extraInt)
val metadata = Metadata(CLASS_KIND, metadataVersion, d1, d2, extraInt = extraInt)
return Class(metadata)
}
}
@@ -89,7 +89,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
/**
* Represents metadata of a class file containing a compiled Kotlin file facade.
*/
class FileFacade internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header) {
class FileFacade internal constructor(header: Metadata) : KotlinClassMetadata(header) {
private val packageData by lazy(PUBLICATION) {
val data1 = (header.data1.takeIf(Array<*>::isNotEmpty)
?: throw InconsistentKotlinMetadataException("data1 must not be empty"))
@@ -127,7 +127,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
* Returns the metadata of the file facade that was written with this writer.
*
* @param metadataVersion metadata version to be written to the metadata (see [KotlinClassHeader.metadataVersion]),
* [KotlinClassHeader.COMPATIBLE_METADATA_VERSION] by default. Cannot be less (lexicographically) than `[1, 4]`
* [KotlinClassMetadata.COMPATIBLE_METADATA_VERSION] by default. Cannot be less (lexicographically) than `[1, 4]`
* @param extraInt the value of the class-level flags to be written to the metadata (see [KotlinClassHeader.extraInt]),
* 0 by default
*/
@@ -137,12 +137,12 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
level = DeprecationLevel.ERROR
)
fun write(
metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): FileFacade {
checkMetadataVersion(metadataVersion)
val (d1, d2) = writeProtoBufData(t.build(), c)
val metadata = KotlinClassHeader(KotlinClassHeader.FILE_FACADE_KIND, metadataVersion, d1, d2, null, null, extraInt)
val metadata = Metadata(FILE_FACADE_KIND, metadataVersion, d1, d2, extraInt = extraInt)
return FileFacade(metadata)
}
}
@@ -152,7 +152,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
* Represents metadata of a class file containing a synthetic class, e.g. a class for lambda, `$DefaultImpls` class for interface
* method implementations, `$WhenMappings` class for optimized `when` over enums, etc.
*/
class SyntheticClass internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header) {
class SyntheticClass internal constructor(header: Metadata) : KotlinClassMetadata(header) {
private val functionData by lazy(PUBLICATION) {
header.data1.takeIf(Array<*>::isNotEmpty)?.let { data1 ->
JvmProtoBufUtil.readFunctionDataFrom(data1, header.data2)
@@ -208,7 +208,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
* Returns the metadata of the synthetic class that was written with this writer.
*
* @param metadataVersion metadata version to be written to the metadata (see [KotlinClassHeader.metadataVersion]),
* [KotlinClassHeader.COMPATIBLE_METADATA_VERSION] by default. Cannot be less (lexicographically) than `[1, 4]`
* [KotlinClassMetadata.COMPATIBLE_METADATA_VERSION] by default. Cannot be less (lexicographically) than `[1, 4]`
* @param extraInt the value of the class-level flags to be written to the metadata (see [KotlinClassHeader.extraInt]),
* 0 by default
*/
@@ -219,7 +219,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
)
@JvmOverloads
fun write(
metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): SyntheticClass {
checkMetadataVersion(metadataVersion)
@@ -227,7 +227,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
val (d1, d2) =
if (proto != null) writeProtoBufData(proto, c)
else Pair(emptyArray(), emptyArray())
val metadata = KotlinClassHeader(KotlinClassHeader.SYNTHETIC_CLASS_KIND, metadataVersion, d1, d2, null, null, extraInt)
val metadata = Metadata(SYNTHETIC_CLASS_KIND, metadataVersion, d1, d2, extraInt = extraInt)
return SyntheticClass(metadata)
}
}
@@ -238,7 +238,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
*
* @see JvmMultifileClass
*/
class MultiFileClassFacade internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header) {
class MultiFileClassFacade internal constructor(header: Metadata) : KotlinClassMetadata(header) {
/**
* JVM internal names of the part classes which this multi-file class combines.
*/
@@ -257,7 +257,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
*
* @param partClassNames JVM internal names of the part classes which this multi-file class combines
* @param metadataVersion metadata version to be written to the metadata (see [KotlinClassHeader.metadataVersion]),
* [KotlinClassHeader.COMPATIBLE_METADATA_VERSION] by default. Cannot be less (lexicographically) than `[1, 4]`
* [KotlinClassMetadata.COMPATIBLE_METADATA_VERSION] by default. Cannot be less (lexicographically) than `[1, 4]`
* @param extraInt the value of the class-level flags to be written to the metadata (see [KotlinClassHeader.extraInt]),
* 0 by default
*/
@@ -269,13 +269,13 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
@JvmOverloads
fun write(
partClassNames: List<String>,
metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): MultiFileClassFacade {
checkMetadataVersion(metadataVersion)
val metadata = KotlinClassHeader(
KotlinClassHeader.MULTI_FILE_CLASS_FACADE_KIND, metadataVersion,
partClassNames.toTypedArray(), null, null, null, extraInt
val metadata = Metadata(
MULTI_FILE_CLASS_FACADE_KIND, metadataVersion,
partClassNames.toTypedArray(), extraInt = extraInt
)
return MultiFileClassFacade(metadata)
}
@@ -288,7 +288,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
*
* @see JvmMultifileClass
*/
class MultiFileClassPart internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header) {
class MultiFileClassPart internal constructor(header: Metadata) : KotlinClassMetadata(header) {
private val packageData by lazy(PUBLICATION) {
val data1 = (header.data1.takeIf(Array<*>::isNotEmpty)
?: throw InconsistentKotlinMetadataException("data1 must not be empty"))
@@ -333,7 +333,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
*
* @param facadeClassName JVM internal name of the corresponding multi-file class facade
* @param metadataVersion metadata version to be written to the metadata (see [KotlinClassHeader.metadataVersion]),
* [KotlinClassHeader.COMPATIBLE_METADATA_VERSION] by default. Cannot be less (lexicographically) than `[1, 4]`
* [KotlinClassMetadata.COMPATIBLE_METADATA_VERSION] by default. Cannot be less (lexicographically) than `[1, 4]`
* @param extraInt the value of the class-level flags to be written to the metadata (see [KotlinClassHeader.extraInt]),
* 0 by default
*/
@@ -344,13 +344,13 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
@JvmOverloads
fun write(
facadeClassName: String,
metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): MultiFileClassPart {
checkMetadataVersion(metadataVersion)
val (d1, d2) = writeProtoBufData(t.build(), c)
val metadata = KotlinClassHeader(
KotlinClassHeader.MULTI_FILE_CLASS_PART_KIND, metadataVersion, d1, d2, facadeClassName, null, extraInt
val metadata = Metadata(
MULTI_FILE_CLASS_PART_KIND, metadataVersion, d1, d2, facadeClassName, extraInt = extraInt
)
return MultiFileClassPart(metadata)
}
@@ -361,7 +361,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
* Represents metadata of an unknown class file. This class is used if an old version of this library is used against a new kind
* of class files generated by the Kotlin compiler, unsupported by this library.
*/
class Unknown internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header)
class Unknown internal constructor(header: Metadata) : KotlinClassMetadata(header)
companion object {
// TODO: docs
@@ -369,7 +369,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
@Suppress("DEPRECATION_ERROR")
fun writeClass(
kmClass: KmClass,
metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): Class = KotlinClassMetadata.Class.Writer().also { kmClass.accept(it) }.write(metadataVersion, extraInt)
@@ -378,7 +378,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
@Suppress("DEPRECATION_ERROR")
fun writeFileFacade(
kmPackage: KmPackage,
metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): FileFacade = FileFacade.Writer().also { kmPackage.accept(it) }.write(metadataVersion, extraInt)
@@ -386,20 +386,20 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
@Suppress("DEPRECATION_ERROR")
fun writeLambda(
kmLambda: KmLambda,
metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): SyntheticClass = SyntheticClass.Writer().also { kmLambda.accept(it) }.write(metadataVersion, extraInt)
@OptIn(DeprecatedVisitor::class)
@Suppress("DEPRECATION_ERROR")
fun writeSyntheticClass(
metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): SyntheticClass = SyntheticClass.Writer().write(metadataVersion, extraInt)
@Suppress("DEPRECATION_ERROR")
fun writeMultiFileClassFacade(
partClassNames: List<String>, metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
partClassNames: List<String>, metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): MultiFileClassFacade = MultiFileClassFacade.Writer().write(partClassNames, metadataVersion, extraInt)
@@ -408,7 +408,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
fun writeMultiFileClassPart(
kmPackage: KmPackage,
facadeClassName: String,
metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION,
metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION,
extraInt: Int = 0
): MultiFileClassPart = MultiFileClassPart.Writer().also { kmPackage.accept(it) }.write(facadeClassName, metadataVersion, extraInt)
@@ -423,7 +423,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
* @param header the header of a Kotlin JVM class file to be parsed
*/
@JvmStatic
fun read(header: KotlinClassHeader): KotlinClassMetadata? {
fun read(header: Metadata): KotlinClassMetadata? {
if (!JvmMetadataVersion(
header.metadataVersion,
(header.extraInt and (1 shl 3)/* see JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG */) != 0
@@ -432,11 +432,11 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
return try {
when (header.kind) {
KotlinClassHeader.CLASS_KIND -> Class(header)
KotlinClassHeader.FILE_FACADE_KIND -> FileFacade(header)
KotlinClassHeader.SYNTHETIC_CLASS_KIND -> SyntheticClass(header)
KotlinClassHeader.MULTI_FILE_CLASS_FACADE_KIND -> MultiFileClassFacade(header)
KotlinClassHeader.MULTI_FILE_CLASS_PART_KIND -> MultiFileClassPart(header)
CLASS_KIND -> Class(header)
FILE_FACADE_KIND -> FileFacade(header)
SYNTHETIC_CLASS_KIND -> SyntheticClass(header)
MULTI_FILE_CLASS_FACADE_KIND -> MultiFileClassFacade(header)
MULTI_FILE_CLASS_PART_KIND -> MultiFileClassPart(header)
else -> Unknown(header)
}
} catch (e: InconsistentKotlinMetadataException) {
@@ -452,5 +452,54 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
"Please change the version from ${version.toList()} to at least [1, 4]."
}
}
/**
* A class file kind signifying that the corresponding class file contains a declaration of a Kotlin class.
*
* @see Metadata.kind
*/
const val CLASS_KIND = 1
/**
* A class file kind signifying that the corresponding class file is a compiled Kotlin file facade.
*
* @see Metadata.kind
*/
const val FILE_FACADE_KIND = 2
/**
* A class file kind signifying that the corresponding class file is synthetic, e.g. it's a class for lambda, `$DefaultImpls` class
* for interface method implementations, `$WhenMappings` class for optimized `when` over enums, etc.
*
* @see Metadata.kind
*/
const val SYNTHETIC_CLASS_KIND = 3
/**
* A class file kind signifying that the corresponding class file is a compiled multi-file class facade.
*
* @see Metadata.kind
*
* @see JvmMultifileClass
*/
const val MULTI_FILE_CLASS_FACADE_KIND = 4
/**
* A class file kind signifying that the corresponding class file is a compiled multi-file class part, i.e. an internal class
* with method bodies and their metadata, accessed only from the corresponding facade.
*
* @see Metadata.kind
*
* @see JvmMultifileClass
*/
const val MULTI_FILE_CLASS_PART_KIND = 5
/**
* The latest metadata version supported by this version of the library.
*
* @see Metadata.metadataVersion
*/
@JvmField // TODO: move it somewhere since it is also used in KotlinModuleMetadata?
val COMPATIBLE_METADATA_VERSION = JvmMetadataVersion.INSTANCE.toArray().copyOf()
}
}
@@ -9,6 +9,7 @@ package kotlinx.metadata.jvm
import kotlinx.metadata.*
import kotlinx.metadata.impl.accept
import kotlinx.metadata.jvm.KotlinClassMetadata.Companion.COMPATIBLE_METADATA_VERSION
import org.jetbrains.kotlin.metadata.jvm.JvmModuleProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
@@ -83,11 +84,11 @@ class KotlinModuleMetadata(@Suppress("CanBeParameter", "MemberVisibilityCanBePri
/**
* Returns the metadata of the module file that was written with this writer.
*
* @param metadataVersion metadata version to be written to the metadata (see [KotlinClassHeader.metadataVersion]),
* [KotlinClassHeader.COMPATIBLE_METADATA_VERSION] by default
* @param metadataVersion metadata version to be written to the metadata (see [Metadata.metadataVersion]),
* [KotlinClassMetadata.COMPATIBLE_METADATA_VERSION] by default
*/
@Deprecated("Writer class API is deprecated. Please use KotlinModuleMetadata.write(kmModule, metadataVersion)", level = DeprecationLevel.ERROR)
fun write(metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION): KotlinModuleMetadata =
fun write(metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION): KotlinModuleMetadata =
KotlinModuleMetadata(b.build().serializeToByteArray(JvmMetadataVersion(*metadataVersion), 0))
}
@@ -144,7 +145,7 @@ class KotlinModuleMetadata(@Suppress("CanBeParameter", "MemberVisibilityCanBePri
@OptIn(DeprecatedVisitor::class)
@Suppress("DEPRECATION_ERROR")
fun write(kmModule: KmModule, metadataVersion: IntArray = KotlinClassHeader.COMPATIBLE_METADATA_VERSION): KotlinModuleMetadata = Writer().also { kmModule.accept(it) }.write(metadataVersion)
fun write(kmModule: KmModule, metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION): KotlinModuleMetadata = Writer().also { kmModule.accept(it) }.write(metadataVersion)
}
}
@@ -18,3 +18,27 @@ val ClassName.jvmInternalName: String
get() =
if (this.isLocal) substring(1)
else replace('.', '$')
/**
* Helper function to instantiate [Metadata].
* In contrary to direct constructor call, this one accept nullable parameters to substitute nulls with default values.
* Also, this one does not accept [Metadata.bytecodeVersion] as it is deprecated.
*/
fun Metadata(
kind: Int? = null,
metadataVersion: IntArray? = null,
data1: Array<String>? = null,
data2: Array<String>? = null,
extraString: String? = null,
packageName: String? = null,
extraInt: Int? = null
): Metadata = Metadata(
kind ?: 1,
metadataVersion ?: intArrayOf(),
intArrayOf(1, 0, 3),
data1 ?: emptyArray(),
data2 ?: emptyArray(),
extraString ?: "",
packageName ?: "",
extraInt ?: 0
)
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.test;
import kotlin.Metadata;
import kotlinx.metadata.KmClass;
import kotlinx.metadata.jvm.KotlinClassHeader;
import kotlinx.metadata.jvm.KotlinClassMetadata;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class JavaUsageTest {
@SuppressWarnings("ConstantConditions")
@Test
public void testKotlinClassHeader() {
Metadata m = MetadataSmokeTest.class.getAnnotation(Metadata.class);
KmClass clazz1 = ((KotlinClassMetadata.Class) KotlinClassMetadata.read(m)).toKmClass();
KotlinClassHeader kh = new KotlinClassHeader(m.k(), m.mv(),m.d1(),m.d2(), m.xs(), m.pn(), m.xi());
KmClass clazz2 = ((KotlinClassMetadata.Class) KotlinClassMetadata.read(kh)).toKmClass();
assertEquals(clazz1.getName(), clazz2.getName());
}
}
@@ -17,10 +17,8 @@ import kotlin.test.*
@OptIn(DeprecatedVisitor::class)
class MetadataSmokeTest {
private fun Class<*>.readMetadata(): KotlinClassHeader {
return getAnnotation(Metadata::class.java).run {
KotlinClassHeader(kind, metadataVersion, data1, data2, extraString, packageName, extraInt)
}
private fun Class<*>.readMetadata(): Metadata {
return getAnnotation(Metadata::class.java)
}
@Test
@@ -155,17 +153,7 @@ class MetadataSmokeTest {
fun lambdaVersionRequirement() {
val x: suspend Int.(String, String) -> Unit = { _, _ -> }
val annotation = x::class.java.getAnnotation(Metadata::class.java)!!
val metadata = KotlinClassMetadata.read(
KotlinClassHeader(
kind = annotation.kind,
metadataVersion = annotation.metadataVersion,
data1 = annotation.data1,
data2 = annotation.data2,
extraInt = annotation.extraInt,
extraString = annotation.extraString,
packageName = annotation.packageName
)
) as KotlinClassMetadata.SyntheticClass
val metadata = KotlinClassMetadata.read(annotation) as KotlinClassMetadata.SyntheticClass
metadata.accept(KmLambda())
}
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.kotlinp
import kotlinx.metadata.jvm.KotlinClassHeader
import kotlinx.metadata.jvm.Metadata
import org.jetbrains.org.objectweb.asm.*
import java.io.File
import java.io.FileInputStream
internal fun File.readKotlinClassHeader(): KotlinClassHeader? {
var header: KotlinClassHeader? = null
internal fun File.readKotlinClassHeader(): Metadata? {
var header: Metadata? = null
try {
val metadataDesc = Type.getDescriptor(Metadata::class.java)
@@ -27,7 +27,7 @@ internal fun File.readKotlinClassHeader(): KotlinClassHeader? {
return header
}
private fun readMetadataVisitor(output: (KotlinClassHeader) -> Unit): AnnotationVisitor =
private fun readMetadataVisitor(output: (Metadata) -> Unit): AnnotationVisitor =
object : AnnotationVisitor(Opcodes.API_VERSION) {
var kind: Int? = null
var metadataVersion: IntArray? = null
@@ -69,6 +69,6 @@ private fun readMetadataVisitor(output: (KotlinClassHeader) -> Unit): Annotation
}
override fun visitEnd() {
output(KotlinClassHeader(kind, metadataVersion, data1, data2, extraString, packageName, extraInt))
output(Metadata(kind, metadataVersion, data1, data2, extraString, packageName, extraInt))
}
}