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

Added a factory that creates an enum serializer with annotations on the class #2125

Merged
merged 2 commits into from
Dec 14, 2022
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
28 changes: 27 additions & 1 deletion core/commonMain/src/kotlinx/serialization/internal/Enums.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package kotlinx.serialization.internal
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlin.jvm.Volatile

/*
* Descriptor used for explicitly serializable enums by the plugin.
Expand Down Expand Up @@ -56,6 +55,9 @@ internal fun <T : Enum<T>> createSimpleEnumSerializer(serialName: String, values
return EnumSerializer(serialName, values)
}

/**
* The function has a bug (#2121) and should not be used by new (1.8.20+) plugins. It is preserved for backward compatibility with previously compiled enum classes.
*/
@OptIn(ExperimentalSerializationApi::class)
@InternalSerializationApi
internal fun <T : Enum<T>> createMarkedEnumSerializer(
Expand All @@ -76,6 +78,30 @@ internal fun <T : Enum<T>> createMarkedEnumSerializer(
return EnumSerializer(serialName, values, descriptor)
}

@OptIn(ExperimentalSerializationApi::class)
@InternalSerializationApi
internal fun <T : Enum<T>> createAnnotatedEnumSerializer(
serialName: String,
values: Array<T>,
names: Array<String?>,
entryAnnotations: Array<Array<Annotation>?>,
classAnnotations: Array<Annotation>?
): KSerializer<T> {
val descriptor = EnumDescriptor(serialName, values.size)
classAnnotations?.forEach {
descriptor.pushClassAnnotation(it)
}
values.forEachIndexed { i, v ->
val elementName = names.getOrNull(i) ?: v.name
descriptor.addElement(elementName)
entryAnnotations.getOrNull(i)?.forEach {
descriptor.pushAnnotation(it)
}
}

return EnumSerializer(serialName, values, descriptor)
}

@PublishedApi
@OptIn(ExperimentalSerializationApi::class)
internal class EnumSerializer<T : Enum<T>>(
Expand Down
105 changes: 105 additions & 0 deletions core/commonTest/src/kotlinx/serialization/EnumDescriptorsTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.serialization

import kotlinx.serialization.descriptors.SerialDescriptor
import kotlin.test.Test
import kotlin.test.assertEquals


class EnumDescriptorsTest {

@Serializable
enum class SerializableEnum {
A,
B
}

@SerialInfo
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
annotation class SerialAnnotation(val text: String)

@SerialAnnotation("On Class")
@Serializable
enum class FullyAnnotatedEnum {
@SerialAnnotation("On A")
A,

@SerialAnnotation("On B")
B
}

@Serializable
enum class EntriesAnnotatedEnum {
@SerialAnnotation("On A")
A,

@SerialAnnotation("On B")
B
}

@SerialAnnotation("On Class")
@Serializable
enum class ClassAnnotatedEnum {
A,
B
}

@Test
fun testSerializableEnum() {
val d = SerializableEnum.serializer().descriptor
assertEquals("kotlinx.serialization.EnumDescriptorsTest.SerializableEnum", d.serialName)

assertEquals("A", d.getElementName(0))
assertEquals("B", d.getElementName(1))
}

@Test
fun testFullyAnnotatedEnum() {
assertFullyAnnotated(FullyAnnotatedEnum.serializer().descriptor)
assertFullyAnnotated(serializer<FullyAnnotatedEnum>().descriptor)
}

@Test
fun testEntriesAnnotatedEnum() {
assertEntriesAnnotated(EntriesAnnotatedEnum.serializer().descriptor)
assertEntriesAnnotated(serializer<EntriesAnnotatedEnum>().descriptor)
}

@Test
fun testClassAnnotatedEnum() {
assertClassAnnotated(ClassAnnotatedEnum.serializer().descriptor)
assertClassAnnotated(serializer<ClassAnnotatedEnum>().descriptor)
}

private fun assertFullyAnnotated(descriptor: SerialDescriptor) {
// plugin changes are expected, delete and uncomment when this condition will fail
assertEquals(0, descriptor.annotations.size)
// assertEquals(1, descriptor.annotations.size)
// assertEquals("On Class", (descriptor.annotations.first() as SerialAnnotation).text)

assertEquals(1, descriptor.getElementAnnotations(0).size)
assertEquals("On A", (descriptor.getElementAnnotations(0).first() as SerialAnnotation).text)

assertEquals(1, descriptor.getElementAnnotations(1).size)
assertEquals("On B", (descriptor.getElementAnnotations(1).first() as SerialAnnotation).text)
}

private fun assertEntriesAnnotated(descriptor: SerialDescriptor) {
assertEquals(1, descriptor.getElementAnnotations(0).size)
assertEquals("On A", (descriptor.getElementAnnotations(0).first() as SerialAnnotation).text)

assertEquals(1, descriptor.getElementAnnotations(1).size)
assertEquals("On B", (descriptor.getElementAnnotations(1).first() as SerialAnnotation).text)
}

private fun assertClassAnnotated(descriptor: SerialDescriptor) {
// plugin changes are expected, delete and uncomment when this condition will fail
assertEquals(0, descriptor.annotations.size)
// assertEquals(1, descriptor.annotations.size)
// assertEquals("On Class", (descriptor.annotations.first() as SerialAnnotation).text)
}

}