From 96f475ea2a58863aa3d3d728f1040d41add9c963 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 25 Aug 2021 22:27:09 +0200 Subject: [PATCH] Support serialization of collections that are not lists So far there was an implicit assumption hard-coded that collections are always lists. However, sets are also collections, and can be serialized to JSON arrays just like lists. This change allows to serialize generic collections independently of the concrete implementation. Fixes #1421. --- .../internal/CollectionSerializers.kt | 23 ++++++----- .../features/CollectionSerializerTest.kt | 41 +++++++++++++++++++ 2 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 formats/json/commonTest/src/kotlinx/serialization/features/CollectionSerializerTest.kt diff --git a/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt b/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt index 91b4e713f..d66e1c545 100644 --- a/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt +++ b/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt @@ -202,12 +202,17 @@ internal class ReferenceArraySerializer, B>(element: KSerializer) : ListLikeSerializer(element) { + override fun C.collectionSize(): Int = size + override fun C.collectionIterator(): Iterator = iterator() +} + @InternalSerializationApi @PublishedApi -internal class ArrayListSerializer(element: KSerializer) : ListLikeSerializer, ArrayList>(element) { +internal class ArrayListSerializer(element: KSerializer) : CollectionSerializer, ArrayList>(element) { override val descriptor: SerialDescriptor = ArrayListClassDesc(element.descriptor) - override fun List.collectionSize(): Int = size - override fun List.collectionIterator(): Iterator = iterator() + override fun builder(): ArrayList = arrayListOf() override fun ArrayList.builderSize(): Int = size override fun ArrayList.toResult(): List = this @@ -219,11 +224,9 @@ internal class ArrayListSerializer(element: KSerializer) : ListLikeSeriali @PublishedApi internal class LinkedHashSetSerializer( eSerializer: KSerializer -) : ListLikeSerializer, LinkedHashSet>(eSerializer) { - +) : CollectionSerializer, LinkedHashSet>(eSerializer) { override val descriptor: SerialDescriptor = LinkedHashSetClassDesc(eSerializer.descriptor) - override fun Set.collectionSize(): Int = size - override fun Set.collectionIterator(): Iterator = iterator() + override fun builder(): LinkedHashSet = linkedSetOf() override fun LinkedHashSet.builderSize(): Int = size override fun LinkedHashSet.toResult(): Set = this @@ -235,11 +238,9 @@ internal class LinkedHashSetSerializer( @PublishedApi internal class HashSetSerializer( eSerializer: KSerializer -) : ListLikeSerializer, HashSet>(eSerializer) { - +) : CollectionSerializer, HashSet>(eSerializer) { override val descriptor: SerialDescriptor = HashSetClassDesc(eSerializer.descriptor) - override fun Set.collectionSize(): Int = size - override fun Set.collectionIterator(): Iterator = iterator() + override fun builder(): HashSet = HashSet() override fun HashSet.builderSize(): Int = size override fun HashSet.toResult(): Set = this diff --git a/formats/json/commonTest/src/kotlinx/serialization/features/CollectionSerializerTest.kt b/formats/json/commonTest/src/kotlinx/serialization/features/CollectionSerializerTest.kt new file mode 100644 index 000000000..ca8116a0b --- /dev/null +++ b/formats/json/commonTest/src/kotlinx/serialization/features/CollectionSerializerTest.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.serialization.features + +import kotlinx.serialization.* +import kotlinx.serialization.builtins.* +import kotlinx.serialization.json.Json +import kotlinx.serialization.test.* +import kotlin.test.* + +class CollectionSerializerTest { + + @Serializable + data class CollectionWrapper( + val collection: Collection + ) + + @Test + fun testListJson() { + val list = listOf("foo", "bar", "foo", "bar") + + val string = Json.encodeToString(CollectionWrapper(list)) + assertEquals("""{"collection":["foo","bar","foo","bar"]}""", string) + + val wrapper = Json.decodeFromString(string) + assertEquals(list, wrapper.collection) + } + + @Test + fun testSetJson() { + val set = setOf("foo", "bar", "foo", "bar") + + val string = Json.encodeToString(CollectionWrapper(set)) + assertEquals("""{"collection":["foo","bar"]}""", string) + + val wrapper = Json.decodeFromString(string) + assertEquals(set.toList(), wrapper.collection) + } +}