Skip to content

Commit

Permalink
feat: Make accessible the original descriptor when nullable (#2631)
Browse files Browse the repository at this point in the history
  • Loading branch information
Chuckame committed Apr 18, 2024
1 parent 84f5e8a commit 56b5c50
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 0 deletions.
1 change: 1 addition & 0 deletions core/api/kotlinx-serialization-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ public final class kotlinx/serialization/descriptors/SerialDescriptorsKt {
public static synthetic fun buildClassSerialDescriptor$default (Ljava/lang/String;[Lkotlinx/serialization/descriptors/SerialDescriptor;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/serialization/descriptors/SerialDescriptor;
public static final fun buildSerialDescriptor (Ljava/lang/String;Lkotlinx/serialization/descriptors/SerialKind;[Lkotlinx/serialization/descriptors/SerialDescriptor;Lkotlin/jvm/functions/Function1;)Lkotlinx/serialization/descriptors/SerialDescriptor;
public static synthetic fun buildSerialDescriptor$default (Ljava/lang/String;Lkotlinx/serialization/descriptors/SerialKind;[Lkotlinx/serialization/descriptors/SerialDescriptor;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/serialization/descriptors/SerialDescriptor;
public static final fun getNonNullOriginal (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/descriptors/SerialDescriptor;
public static final fun getNullable (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/descriptors/SerialDescriptor;
public static final fun listSerialDescriptor (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/descriptors/SerialDescriptor;
public static final fun mapSerialDescriptor (Lkotlinx/serialization/descriptors/SerialDescriptor;Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/descriptors/SerialDescriptor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,24 @@ public val SerialDescriptor.nullable: SerialDescriptor
return SerialDescriptorForNullable(this)
}

/**
* Returns non-nullable serial descriptor for the type if this descriptor has been auto-generated (plugin
* generated descriptors) or created with `.nullable` extension on a descriptor or serializer.
*
* Otherwise, returns this.
*
* It may return nullable descriptor if this descriptor has been created manually as nullable by directly implementing SerialDescriptor interface.
*
* @see SerialDescriptor.nullable
* @see KSerializer.nullable
*/
@ExperimentalSerializationApi
public val SerialDescriptor.nonNullOriginal: SerialDescriptor
get() = when (this) {
is SerialDescriptorForNullable -> original
else -> this
}

/**
* Builder for [SerialDescriptor] for user-defined serializers.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,44 @@ class SerialDescriptorBuilderTest {
assertTrue(descriptor.isNullable)
assertEquals("my.Simple?", descriptor.serialName)
}

@Test
fun testNonNullOriginal() {
listOf(
buildClassSerialDescriptor("my.Simple") {},
Boolean.serializer().descriptor,
String.serializer().descriptor,
ListSerializer(Int.serializer()).descriptor,
).forEach { originalDescriptor ->
// Unwrapping original descriptor when it is not nullable should return the same descriptor (no-op operation)
assertSame(originalDescriptor.nonNullOriginal, originalDescriptor)

// Unwrapping original descriptor when it is nullable should return the original descriptor
assertSame(originalDescriptor.nullable.nonNullOriginal, originalDescriptor)
}

// Unwrapping original descriptor of a custom nullable descriptor should return the same descriptor
val customNullableDescriptor = CustomNullableDescriptor()
assertSame(customNullableDescriptor.nonNullOriginal, customNullableDescriptor)

// Unwrapping original descriptor of a nullable field should return the original non-null descriptor
assertSame(Type.serializer().descriptor.getElementDescriptor(0).nonNullOriginal, String.serializer().descriptor)

}

@Serializable
class Type(val field: String?)

private class CustomNullableDescriptor : SerialDescriptor {
override val isNullable: Boolean = true

override val serialName: String = "CustomNullableDescriptor"
override val kind: SerialKind = PrimitiveKind.STRING
override val elementsCount: Int = 0
override fun getElementName(index: Int): String = error("Should not be called")
override fun getElementIndex(name: String): Int = error("Should not be called")
override fun isElementOptional(index: Int): Boolean = error("Should not be called")
override fun getElementAnnotations(index: Int): List<Annotation> = error("Should not be called")
override fun getElementDescriptor(index: Int): SerialDescriptor = error("Should not be called")
}
}

0 comments on commit 56b5c50

Please sign in to comment.