Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add serializer for kotlin.uuid.Uuid [for Kotlin 2.0.20] #2744

Merged
merged 1 commit into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ kotlin {
progressiveMode = true

optIn("kotlin.ExperimentalMultiplatform")
optIn("kotlin.ExperimentalStdlibApi")
optIn("kotlinx.serialization.InternalSerializationApi")
}
}
Expand Down
10 changes: 10 additions & 0 deletions core/api/kotlinx-serialization-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public final class kotlinx/serialization/builtins/BuiltinSerializersKt {
public static final fun serializer (Lkotlin/jvm/internal/ShortCompanionObject;)Lkotlinx/serialization/KSerializer;
public static final fun serializer (Lkotlin/jvm/internal/StringCompanionObject;)Lkotlinx/serialization/KSerializer;
public static final fun serializer (Lkotlin/time/Duration$Companion;)Lkotlinx/serialization/KSerializer;
public static final fun serializer (Lkotlin/uuid/Uuid$Companion;)Lkotlinx/serialization/KSerializer;
}

public final class kotlinx/serialization/builtins/LongAsStringSerializer : kotlinx/serialization/KSerializer {
Expand Down Expand Up @@ -1293,6 +1294,15 @@ public final class kotlinx/serialization/internal/UnitSerializer : kotlinx/seria
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlin/Unit;)V
}

public final class kotlinx/serialization/internal/UuidSerializer : kotlinx/serialization/KSerializer {
public static final field INSTANCE Lkotlinx/serialization/internal/UuidSerializer;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlin/uuid/Uuid;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlin/uuid/Uuid;)V
}

public final class kotlinx/serialization/modules/PolymorphicModuleBuilder {
public fun <init> (Lkotlin/reflect/KClass;Lkotlinx/serialization/KSerializer;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lkotlinx/serialization/KSerializer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
Expand Down
9 changes: 9 additions & 0 deletions core/api/kotlinx-serialization-core.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,14 @@ final object kotlinx.serialization.internal/UnitSerializer : kotlinx.serializati
final fun serialize(kotlinx.serialization.encoding/Encoder, kotlin/Unit) // kotlinx.serialization.internal/UnitSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlin.Unit){}[0]
}

final object kotlinx.serialization.internal/UuidSerializer : kotlinx.serialization/KSerializer<kotlin.uuid/Uuid> { // kotlinx.serialization.internal/UuidSerializer|null[0]
final val descriptor // kotlinx.serialization.internal/UuidSerializer.descriptor|{}descriptor[0]
final fun <get-descriptor>(): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.serialization.internal/UuidSerializer.descriptor.<get-descriptor>|<get-descriptor>(){}[0]

final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlin.uuid/Uuid // kotlinx.serialization.internal/UuidSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0]
final fun serialize(kotlinx.serialization.encoding/Encoder, kotlin.uuid/Uuid) // kotlinx.serialization.internal/UuidSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlin.uuid.Uuid){}[0]
}

final val kotlinx.serialization.builtins/nullable // kotlinx.serialization.builtins/nullable|@kotlinx.serialization.KSerializer<0:0>{0§<kotlin.Any>}nullable[0]
final fun <#A1: kotlin/Any> (kotlinx.serialization/KSerializer<#A1>).<get-nullable>(): kotlinx.serialization/KSerializer<#A1?> // kotlinx.serialization.builtins/nullable.<get-nullable>|<get-nullable>@kotlinx.serialization.KSerializer<0:0>(){0§<kotlin.Any>}[0]
final val kotlinx.serialization.descriptors/capturedKClass // kotlinx.serialization.descriptors/capturedKClass|@kotlinx.serialization.descriptors.SerialDescriptor{}capturedKClass[0]
Expand All @@ -1062,6 +1070,7 @@ final val kotlinx.serialization.modules/EmptySerializersModule // kotlinx.serial
final fun <get-EmptySerializersModule>(): kotlinx.serialization.modules/SerializersModule // kotlinx.serialization.modules/EmptySerializersModule.<get-EmptySerializersModule>|<get-EmptySerializersModule>(){}[0]

final fun (kotlin.time/Duration.Companion).kotlinx.serialization.builtins/serializer(): kotlinx.serialization/KSerializer<kotlin.time/Duration> // kotlinx.serialization.builtins/serializer|serializer@kotlin.time.Duration.Companion(){}[0]
final fun (kotlin.uuid/Uuid.Companion).kotlinx.serialization.builtins/serializer(): kotlinx.serialization/KSerializer<kotlin.uuid/Uuid> // kotlinx.serialization.builtins/serializer|serializer@kotlin.uuid.Uuid.Companion(){}[0]
final fun (kotlin/Boolean.Companion).kotlinx.serialization.builtins/serializer(): kotlinx.serialization/KSerializer<kotlin/Boolean> // kotlinx.serialization.builtins/serializer|serializer@kotlin.Boolean.Companion(){}[0]
final fun (kotlin/Byte.Companion).kotlinx.serialization.builtins/serializer(): kotlinx.serialization/KSerializer<kotlin/Byte> // kotlinx.serialization.builtins/serializer|serializer@kotlin.Byte.Companion(){}[0]
final fun (kotlin/Char.Companion).kotlinx.serialization.builtins/serializer(): kotlinx.serialization/KSerializer<kotlin/Char> // kotlinx.serialization.builtins/serializer|serializer@kotlin.Char.Companion(){}[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import kotlinx.serialization.internal.*
import kotlin.reflect.*
import kotlinx.serialization.descriptors.*
import kotlin.time.Duration
import kotlin.uuid.*

/**
* Returns a nullable serializer for the given serializer of non-null type.
Expand Down Expand Up @@ -251,6 +252,20 @@ public fun UShort.Companion.serializer(): KSerializer<UShort> = UShortSerializer
*/
public fun Duration.Companion.serializer(): KSerializer<Duration> = DurationSerializer

/**
* Returns serializer for [Uuid].
* Serializer operates with a standard UUID string representation, also known as "hex-and-dash" format —
sandwwraith marked this conversation as resolved.
Show resolved Hide resolved
* [RFC 9562 section 4](https://www.rfc-editor.org/rfc/rfc9562.html#section-4).
*
* Serialization always produces lowercase string, deserialization is case-insensitive.
* More details can be found in the documentation of [Uuid.toString] and [Uuid.parse] functions.
*
* @see Uuid.toString
* @see Uuid.parse
*/
@ExperimentalUuidApi
public fun Uuid.Companion.serializer(): KSerializer<Uuid> = UuidSerializer

/**
* Returns serializer for [Nothing].
* Throws an exception when trying to encode or decode.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlin.time.Duration
import kotlin.uuid.*


@PublishedApi
Expand Down Expand Up @@ -37,3 +38,17 @@ internal object NothingSerializer : KSerializer<Nothing> {
throw SerializationException("'kotlin.Nothing' does not have instances")
}
}

@PublishedApi
@ExperimentalUuidApi
internal object UuidSerializer: KSerializer<Uuid> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("kotlin.uuid.Uuid", PrimitiveKind.STRING)

override fun serialize(encoder: Encoder, value: Uuid) {
encoder.encodeString(value.toString())
}

override fun deserialize(decoder: Decoder): Uuid {
return Uuid.parse(decoder.decodeString())
shanshin marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlin.native.concurrent.*
import kotlin.reflect.*
import kotlin.time.Duration
import kotlin.uuid.*

@OptIn(ExperimentalUnsignedTypes::class)
@OptIn(ExperimentalUnsignedTypes::class, ExperimentalUuidApi::class)
private val BUILTIN_SERIALIZERS = mapOf(
String::class to String.serializer(),
Char::class to Char.serializer(),
Expand Down Expand Up @@ -44,7 +44,8 @@ private val BUILTIN_SERIALIZERS = mapOf(
BooleanArray::class to BooleanArraySerializer(),
Unit::class to Unit.serializer(),
Nothing::class to NothingSerializer(),
Duration::class to Duration.serializer()
Duration::class to Duration.serializer(),
Uuid::class to Uuid.serializer()
)

internal class PrimitiveSerialDescriptor(
Expand Down
1 change: 1 addition & 0 deletions formats/json-tests/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ kotlin {
sourceSets {
configureEach {
languageSettings {
optIn("kotlin.uuid.ExperimentalUuidApi")
optIn("kotlinx.serialization.internal.CoreFriendModuleApi")
optIn("kotlinx.serialization.json.internal.JsonFriendModuleApi")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import kotlinx.serialization.test.*
import kotlin.reflect.*
import kotlin.test.*
import kotlin.time.Duration
import kotlin.uuid.*

@Suppress("RemoveExplicitTypeArguments") // This is exactly what's being tested
class SerializersLookupTest : JsonTestBase() {
Expand Down Expand Up @@ -141,6 +142,14 @@ class SerializersLookupTest : JsonTestBase() {
assertSame(Duration.serializer(), serializer<Duration>())
}

@Test
@OptIn(ExperimentalUuidApi::class)
fun testLookupUuid() {
assertSame<KSerializer<*>?>(Uuid.serializer(), serializerOrNull(typeOf<Uuid>()))
// TODO: uncomment in 2.1 release
// assertSame<KSerializer<*>?>(Uuid.serializer(), serializer<Uuid>())
}

@Test
fun testCustomGeneric() {
val intBox = Box(42)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.serialization.features

import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
import kotlinx.serialization.json.*
import kotlinx.serialization.modules.*
import kotlin.test.*
import kotlin.uuid.*

class UuidTest : JsonTestBase() {
@Test
fun testPlainUuid() {
val uuid = Uuid.random()
assertJsonFormAndRestored(Uuid.serializer(), uuid, "\"$uuid\"")
}

// TODO: write a test without @Contextual after 2.1.0 release
@Serializable
data class Holder(@Contextual val uuid: Uuid)

val json = Json { serializersModule = serializersModuleOf(Uuid.serializer()) }

@Test
fun testNested() {
val fixed = Uuid.parse("bc501c76-d806-4578-b45e-97a264e280f1")
assertJsonFormAndRestored(
Holder.serializer(),
Holder(fixed),
"""{"uuid":"bc501c76-d806-4578-b45e-97a264e280f1"}""",
json
)
}
}