Skip to content

Commit 67e9259

Browse files
Added a factory that creates an enum serializer with annotations on the class (#2125)
Resolves #2121 Co-authored-by: Leonid Startsev <[email protected]>
1 parent 28f7fcb commit 67e9259

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

core/commonMain/src/kotlinx/serialization/internal/Enums.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package kotlinx.serialization.internal
77
import kotlinx.serialization.*
88
import kotlinx.serialization.descriptors.*
99
import kotlinx.serialization.encoding.*
10-
import kotlin.jvm.Volatile
1110

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

58+
/**
59+
* 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.
60+
*/
5961
@OptIn(ExperimentalSerializationApi::class)
6062
@InternalSerializationApi
6163
internal fun <T : Enum<T>> createMarkedEnumSerializer(
@@ -76,6 +78,30 @@ internal fun <T : Enum<T>> createMarkedEnumSerializer(
7678
return EnumSerializer(serialName, values, descriptor)
7779
}
7880

81+
@OptIn(ExperimentalSerializationApi::class)
82+
@InternalSerializationApi
83+
internal fun <T : Enum<T>> createAnnotatedEnumSerializer(
84+
serialName: String,
85+
values: Array<T>,
86+
names: Array<String?>,
87+
entryAnnotations: Array<Array<Annotation>?>,
88+
classAnnotations: Array<Annotation>?
89+
): KSerializer<T> {
90+
val descriptor = EnumDescriptor(serialName, values.size)
91+
classAnnotations?.forEach {
92+
descriptor.pushClassAnnotation(it)
93+
}
94+
values.forEachIndexed { i, v ->
95+
val elementName = names.getOrNull(i) ?: v.name
96+
descriptor.addElement(elementName)
97+
entryAnnotations.getOrNull(i)?.forEach {
98+
descriptor.pushAnnotation(it)
99+
}
100+
}
101+
102+
return EnumSerializer(serialName, values, descriptor)
103+
}
104+
79105
@PublishedApi
80106
@OptIn(ExperimentalSerializationApi::class)
81107
internal class EnumSerializer<T : Enum<T>>(
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization
6+
7+
import kotlinx.serialization.descriptors.SerialDescriptor
8+
import kotlin.test.Test
9+
import kotlin.test.assertEquals
10+
11+
12+
class EnumDescriptorsTest {
13+
14+
@Serializable
15+
enum class SerializableEnum {
16+
A,
17+
B
18+
}
19+
20+
@SerialInfo
21+
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
22+
annotation class SerialAnnotation(val text: String)
23+
24+
@SerialAnnotation("On Class")
25+
@Serializable
26+
enum class FullyAnnotatedEnum {
27+
@SerialAnnotation("On A")
28+
A,
29+
30+
@SerialAnnotation("On B")
31+
B
32+
}
33+
34+
@Serializable
35+
enum class EntriesAnnotatedEnum {
36+
@SerialAnnotation("On A")
37+
A,
38+
39+
@SerialAnnotation("On B")
40+
B
41+
}
42+
43+
@SerialAnnotation("On Class")
44+
@Serializable
45+
enum class ClassAnnotatedEnum {
46+
A,
47+
B
48+
}
49+
50+
@Test
51+
fun testSerializableEnum() {
52+
val d = SerializableEnum.serializer().descriptor
53+
assertEquals("kotlinx.serialization.EnumDescriptorsTest.SerializableEnum", d.serialName)
54+
55+
assertEquals("A", d.getElementName(0))
56+
assertEquals("B", d.getElementName(1))
57+
}
58+
59+
@Test
60+
fun testFullyAnnotatedEnum() {
61+
assertFullyAnnotated(FullyAnnotatedEnum.serializer().descriptor)
62+
assertFullyAnnotated(serializer<FullyAnnotatedEnum>().descriptor)
63+
}
64+
65+
@Test
66+
fun testEntriesAnnotatedEnum() {
67+
assertEntriesAnnotated(EntriesAnnotatedEnum.serializer().descriptor)
68+
assertEntriesAnnotated(serializer<EntriesAnnotatedEnum>().descriptor)
69+
}
70+
71+
@Test
72+
fun testClassAnnotatedEnum() {
73+
assertClassAnnotated(ClassAnnotatedEnum.serializer().descriptor)
74+
assertClassAnnotated(serializer<ClassAnnotatedEnum>().descriptor)
75+
}
76+
77+
private fun assertFullyAnnotated(descriptor: SerialDescriptor) {
78+
// plugin changes are expected, delete and uncomment when this condition will fail
79+
assertEquals(0, descriptor.annotations.size)
80+
// assertEquals(1, descriptor.annotations.size)
81+
// assertEquals("On Class", (descriptor.annotations.first() as SerialAnnotation).text)
82+
83+
assertEquals(1, descriptor.getElementAnnotations(0).size)
84+
assertEquals("On A", (descriptor.getElementAnnotations(0).first() as SerialAnnotation).text)
85+
86+
assertEquals(1, descriptor.getElementAnnotations(1).size)
87+
assertEquals("On B", (descriptor.getElementAnnotations(1).first() as SerialAnnotation).text)
88+
}
89+
90+
private fun assertEntriesAnnotated(descriptor: SerialDescriptor) {
91+
assertEquals(1, descriptor.getElementAnnotations(0).size)
92+
assertEquals("On A", (descriptor.getElementAnnotations(0).first() as SerialAnnotation).text)
93+
94+
assertEquals(1, descriptor.getElementAnnotations(1).size)
95+
assertEquals("On B", (descriptor.getElementAnnotations(1).first() as SerialAnnotation).text)
96+
}
97+
98+
private fun assertClassAnnotated(descriptor: SerialDescriptor) {
99+
// plugin changes are expected, delete and uncomment when this condition will fail
100+
assertEquals(0, descriptor.annotations.size)
101+
// assertEquals(1, descriptor.annotations.size)
102+
// assertEquals("On Class", (descriptor.annotations.first() as SerialAnnotation).text)
103+
}
104+
105+
}

0 commit comments

Comments
 (0)