summaryrefslogtreecommitdiff
path: root/formats/json-tests/commonTest/src/kotlinx/serialization/SerializerForNullableTypeTest.kt
blob: 98f3f5e0deefefe6779e119b5254f1e4956179a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

package kotlinx.serialization

import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.json.*
import kotlinx.serialization.test.*
import kotlin.test.*

public class SerializerForNullableTypeTest : JsonTestBase() {

    // Nullable boxes
    @Serializable(with = StringHolderSerializer::class)
    data class StringHolder(val s: String)

    object StringHolderSerializer : KSerializer<StringHolder?> {
        override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("SHS", PrimitiveKind.STRING).nullable

        override fun serialize(encoder: Encoder, value: StringHolder?) {
            if (value == null) encoder.encodeString("nullable")
            else encoder.encodeString("non-nullable")
        }

        override fun deserialize(decoder: Decoder): StringHolder? {
            if (decoder.decodeNotNullMark()) {
                return StringHolder("non-null: " + decoder.decodeString())
            }
            decoder.decodeNull()
            return StringHolder("nullable")
        }
    }

    @Serializable
    data class Box(val s: StringHolder?)

    @Test
    fun testNullableBoxWithNotNull() {
        val b = Box(StringHolder("box"))
        val string = Json.encodeToString(b)
        assertEquals("""{"s":"non-nullable"}""", string)
        val deserialized = Json.decodeFromString<Box>(string)
        assertEquals(Box(StringHolder("non-null: non-nullable")), deserialized)
    }

    @Test
    fun testNullableBoxWithNull() {
        val b = Box(null)
        val string = Json.encodeToString(b)
        assertEquals("""{"s":"nullable"}""", string)
        val deserialized = Json.decodeFromString<Box>(string)
        assertEquals(Box(StringHolder("non-null: nullable")), deserialized)
    }

    @Test
    fun testNullableBoxDeserializeNull() {
        val deserialized = Json.decodeFromString<Box>("""{"s":null}""")
        assertEquals(Box(StringHolder("nullable")), deserialized)
    }

    // Nullable primitives
    object NullableLongSerializer : KSerializer<Long?> {

        @Serializable
        data class OptionalLong(val initialized: Boolean, val value: Long? = 0)

        override val descriptor: SerialDescriptor = buildClassSerialDescriptor("NLS") {
            element<Boolean>("initialized")
            element<Long?>("value")
        }.nullable

        override fun serialize(encoder: Encoder, value: Long?) {
            val opt = OptionalLong(value != null, value)
            encoder.encodeSerializableValue(OptionalLong.serializer(), opt)
        }

        override fun deserialize(decoder: Decoder): Long? {
            val value = decoder.decodeSerializableValue(OptionalLong.serializer())
            return if (value.initialized) value.value else null
        }
    }

    @Serializable
    data class NullablePrimitive(
        @Serializable(with = NullableLongSerializer::class) val value: Long?
    )

    @Test
    fun testNullableLongWithNotNull() {
        val data = NullablePrimitive(42)
        val json = Json.encodeToString(data)
        assertEquals("""{"value":{"initialized":true,"value":42}}""", Json.encodeToString(data))
        assertEquals(data, Json.decodeFromString(json))
    }

    @Test
    fun testNullableLongWithNull() {
        val data = NullablePrimitive(null)
        val json = Json.encodeToString(data)
        assertEquals("""{"value":{"initialized":false,"value":null}}""", Json.encodeToString(data))
        assertEquals(data, Json.decodeFromString(json))
    }

    // Now generics
    @Serializable
    data class GenericNullableBox<T: Any>(val value: T?)

    @Serializable
    data class GenericBox<T>(val value: T?)

    @Test
    fun testGenericBoxNullable() {
        val data = GenericBox<StringHolder?>(null)
        val json = Json.encodeToString(data)
        assertEquals("""{"value":"nullable"}""", Json.encodeToString(data))
        assertEquals(GenericBox(StringHolder("non-null: nullable")), Json.decodeFromString(json))
    }

    @Test
    fun testGenericNullableBoxFromNull() {
        assertEquals(GenericBox(StringHolder("nullable")), Json.decodeFromString("""{"value":null}"""))
    }

    @Test
    fun testGenericNullableBoxNullable() {
        val data = GenericNullableBox<StringHolder>(null)
        val json = Json.encodeToString(data)
        assertEquals("""{"value":"nullable"}""", Json.encodeToString(data))
        assertEquals(GenericNullableBox(StringHolder("non-null: nullable")), Json.decodeFromString(json))
    }

    @Test
    fun testGenericBoxNullableFromNull() {
        assertEquals(GenericNullableBox(StringHolder("nullable")), Json.decodeFromString("""{"value":null}"""))
    }

}