diff --git a/CHANGELOG.md b/CHANGELOG.md index bb2934b3..93327a28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Update to Kotlin 2.0.21, Gradle 8.10, and Android Gradle Plugin 8.5.2 - Add `wasmWasi` support to `multiplatform-settings-coroutines` and `multiplatform-settings-serialization`. +- Fix an issue in `multiplatform-settings-serialization` where delegates might return wrong values or crash (#217). ## v1.2.0 *(2024-09-01)* ## diff --git a/multiplatform-settings-serialization/src/commonMain/kotlin/SerializationInternals.kt b/multiplatform-settings-serialization/src/commonMain/kotlin/SerializationInternals.kt index 8cf557fb..5e10b9db 100644 --- a/multiplatform-settings-serialization/src/commonMain/kotlin/SerializationInternals.kt +++ b/multiplatform-settings-serialization/src/commonMain/kotlin/SerializationInternals.kt @@ -31,7 +31,7 @@ import kotlinx.serialization.modules.SerializersModule @ExperimentalSerializationApi internal class SettingsEncoder( private val settings: Settings, - key: String, + private val key: String, public override val serializersModule: SerializersModule ) : AbstractEncoder() { @@ -60,6 +60,10 @@ internal class SettingsEncoder( public override fun endStructure(descriptor: SerialDescriptor) { depth-- keyStack.removeLast() + if (keyStack.isEmpty()) { + // We've reached the end of everything, so reset for potential encoder reuse + keyStack.add(key) + } } public override fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder { diff --git a/multiplatform-settings-serialization/src/commonTest/kotlin/SettingsSerializationTest.kt b/multiplatform-settings-serialization/src/commonTest/kotlin/SettingsSerializationTest.kt index 4bd2552e..b041b226 100644 --- a/multiplatform-settings-serialization/src/commonTest/kotlin/SettingsSerializationTest.kt +++ b/multiplatform-settings-serialization/src/commonTest/kotlin/SettingsSerializationTest.kt @@ -21,6 +21,7 @@ import com.russhwolf.settings.MapSettings import com.russhwolf.settings.Settings import com.russhwolf.settings.contains import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationException import kotlinx.serialization.builtins.ListSerializer @@ -1023,6 +1024,46 @@ class SettingsSerializationTest { preferences.list = list assertEquals(expected = list, actual = preferences.list) } + + @Test + fun issue_217() { + val settings = MapSettings() + + @Serializable + data class MyItemDto( + @SerialName("name") + val name: String, + @SerialName("id") + val id: String, + ) + + var myItems: List by settings.serializedValue( + ListSerializer(MyItemDto.serializer()), + "MY_ITEMS", + emptyList(), + ) + + myItems = emptyList() + assertEquals(emptyList(), myItems) + myItems = listOf( + MyItemDto( + name = "Name", + id = "Id", + ) + ) + assertEquals( + listOf( + MyItemDto( + name = "Name", + id = "Id", + ) + ), myItems + ) + + // Should not crash + myItems = emptyList() + myItems = emptyList() + } } @Serializable