kotlinx.serialization
kotlinx.serialization copied to clipboard
Serializing sub-objects raises NPE
Describe the bug Trying to serialize an object inside another object raises a NullPointerException:
Exception in thread "main" java.lang.NullPointerException
at kotlinx.serialization.encoding.Encoder$DefaultImpls.encodeNullableSerializableValue(Encoding.kt:268)
at kotlinx.serialization.json.JsonEncoder$DefaultImpls.encodeNullableSerializableValue(JsonEncoder.kt)
at kotlinx.serialization.json.internal.StreamingJsonEncoder.encodeNullableSerializableValue(StreamingJsonEncoder.kt:15)
at kotlinx.serialization.encoding.AbstractEncoder.encodeNullableSerializableElement(AbstractEncoder.kt:81)
at com.mayak.discord.rest.settings.MessageCreateSettings.write$Self(Settings.kt:13)
at com.mayak.discord.rest.settings.MessageCreateSettings$$serializer.serialize(Settings.kt)
at com.mayak.discord.rest.settings.MessageCreateSettings$$serializer.serialize(Settings.kt:10)
at kotlinx.serialization.json.internal.StreamingJsonEncoder.encodeSerializableValue(StreamingJsonEncoder.kt:223)
at kotlinx.serialization.json.Json.encodeToString(Json.kt:73)
at org.example.MainKt$main$1.invokeSuspend(Main.kt:25)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:86)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:61)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
at org.example.MainKt.main(Main.kt:11)
at org.example.MainKt.main(Main.kt)
To Reproduce Attach a code snippet or test data if possible.
// the code i used for testing
fun main() {
val embed = Embed().apply {
title = "a"
}
val settings = MessageCreateSettings(embed = embed)
println(Json.encodeToString(settings))
}
@Serializable
sealed class Settings
@Serializable
class MessageCreateSettings(
val content: String? = null,
val tts: Boolean = false,
val embed: Embed? = null // error points to this line
): Settings()
@Serializable(with = EmbedSerializer::class)
class Embed private constructor(
var title: String? = null,
var description: String? = null,
@SerialName("fields") internal val _fields: MutableList<EmbedField> = mutableListOf(),
internal val type: String = "rich"
) {
constructor(): this(null)
@Serializable
data class EmbedField(val name: String, val value: String, val inline: Boolean)
val fields: List<EmbedField>
get() = _fields
fun addField(name: String, value: String, inline: Boolean): Embed {
_fields.add(EmbedField(name, value, inline))
return this
}
fun addField(name: String, value: String) = addField(name, value, false)
}
object EmbedSerializer: KSerializer<Embed> {
override val descriptor = Embed.serializer().descriptor
private val mapSerializer = MapSerializer(String.serializer(), JsonElement.serializer())
override fun deserialize(decoder: Decoder): Embed {
val map = decoder.decodeSerializableValue(mapSerializer)
return Embed().apply {
map["title"]?.let { title = Json.decodeFromJsonElement(String.serializer(), it) }
map["description"]?.let { description = Json.decodeFromJsonElement(String.serializer(), it) }
map["fields"]?.jsonArray?.map { f ->
Json.decodeFromJsonElement(Embed.EmbedField.serializer(), f)
}?.forEach(_fields::add)
}
}
override fun serialize(encoder: Encoder, value: Embed) {
val map = mutableMapOf<String, JsonElement>()
map["type"] = Json.encodeToJsonElement(String.serializer(), value.type)
value.title?.let { map["title"] = Json.encodeToJsonElement(String.serializer(), it) }
value.description?.let { map["description"] = Json.encodeToJsonElement(String.serializer(), it) }
if (value.fields.isNotEmpty())
map["fields"] = Json.encodeToJsonElement(value.fields)
encoder.encodeSerializableValue(mapSerializer, map)
}
}
Expected behavior For it to correctly encode the two objects, the embed inside the settings.
Environment
- Kotlin version: 1.4.21
- Library version: 1.0.1
- Kotlin platforms: JVM
- Gradle version: 6.7
- IDE version (if bug is related to the IDE) N/A
- Other relevant context Windows 10, JRE 1.8.0_252