From 661e87ed63e71631a062419a69b0bde96559c18a Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Sun, 9 Jan 2022 11:15:54 +0100 Subject: [PATCH 1/5] CollectionSerializers: Remove redundant visibility modifiers --- .../kotlinx/serialization/internal/CollectionSerializers.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt b/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt index fbd16c58ae..91b4e713f4 100644 --- a/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt +++ b/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt @@ -70,13 +70,13 @@ internal sealed class ListLikeSerializer( } } - protected final override fun readAll(decoder: CompositeDecoder, builder: Builder, startIndex: Int, size: Int) { + final override fun readAll(decoder: CompositeDecoder, builder: Builder, startIndex: Int, size: Int) { require(size >= 0) { "Size must be known in advance when using READ_ALL" } for (index in 0 until size) readElement(decoder, startIndex + index, builder, checkIndex = false) } - protected override fun readElement(decoder: CompositeDecoder, index: Int, builder: Builder, checkIndex: Boolean) { + override fun readElement(decoder: CompositeDecoder, index: Int, builder: Builder, checkIndex: Boolean) { builder.insert(index, decoder.decodeSerializableElement(descriptor, index, elementSerializer)) } } @@ -160,7 +160,7 @@ internal abstract class PrimitiveArraySerializer Date: Sun, 9 Jan 2022 11:23:25 +0100 Subject: [PATCH 2/5] SealedGenericClassesTest: Remove unused variables to avoid warnings --- .../src/kotlinx/serialization/SealedGenericClassesTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/commonTest/src/kotlinx/serialization/SealedGenericClassesTest.kt b/core/commonTest/src/kotlinx/serialization/SealedGenericClassesTest.kt index 150ab7a7f2..7840cd2362 100644 --- a/core/commonTest/src/kotlinx/serialization/SealedGenericClassesTest.kt +++ b/core/commonTest/src/kotlinx/serialization/SealedGenericClassesTest.kt @@ -31,13 +31,13 @@ class SealedGenericClassesTest { // Test that compilation and retrieval is successful @Test fun testQuery() { - val serial1 = Query.SimpleQuery.serializer(String.serializer()) - val serial2 = Query.serializer(UnitSerializer) + Query.SimpleQuery.serializer(String.serializer()) + Query.serializer(UnitSerializer) } @Test fun testFetcher() { - val serial1 = Fetcher.SomethingFetcher.serializer() - val serial2 = Fetcher.serializer(Something.serializer()) + Fetcher.SomethingFetcher.serializer() + Fetcher.serializer(Something.serializer()) } } From 96f475ea2a58863aa3d3d728f1040d41add9c963 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 25 Aug 2021 22:27:09 +0200 Subject: [PATCH 3/5] 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 91b4e713f4..d66e1c5456 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 0000000000..ca8116a0b0 --- /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) + } +} From ed996528ffb441f949179466f27fecfe674eff10 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Sun, 9 Jan 2022 11:20:38 +0100 Subject: [PATCH 4/5] Rename `ListLikeSerializer` to `CollectionLikeSerializer` Now with `CollectionSerializer` inheriting from `ListLikeSerializer`, it makes sense to rename `ListLikeSerializer` to the more generic `CollectionLikeSerializer`. --- .../serialization/internal/CollectionSerializers.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt b/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt index d66e1c5456..fcf4cfa74f 100644 --- a/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt +++ b/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt @@ -54,7 +54,7 @@ public sealed class AbstractCollectionSerializer : } @PublishedApi -internal sealed class ListLikeSerializer( +internal sealed class CollectionLikeSerializer( private val elementSerializer: KSerializer ) : AbstractCollectionSerializer() { @@ -143,7 +143,7 @@ internal abstract class PrimitiveArrayBuilder internal constructor() { internal abstract class PrimitiveArraySerializer> internal constructor( primitiveSerializer: KSerializer -) : ListLikeSerializer(primitiveSerializer) { +) : CollectionLikeSerializer(primitiveSerializer) { final override val descriptor: SerialDescriptor = PrimitiveArrayDescriptor(primitiveSerializer.descriptor) final override fun Builder.builderSize(): Int = position @@ -184,7 +184,7 @@ internal abstract class PrimitiveArraySerializer( private val kClass: KClass, eSerializer: KSerializer -) : ListLikeSerializer, ArrayList>(eSerializer) { +) : CollectionLikeSerializer, ArrayList>(eSerializer) { override val descriptor: SerialDescriptor = ArrayClassDesc(eSerializer.descriptor) override fun Array.collectionSize(): Int = size @@ -203,7 +203,7 @@ internal class ReferenceArraySerializer, B>(element: KSerializer) : ListLikeSerializer(element) { +internal abstract class CollectionSerializer, B>(element: KSerializer) : CollectionLikeSerializer(element) { override fun C.collectionSize(): Int = size override fun C.collectionIterator(): Iterator = iterator() } From dc8e2d6da65dd479ef22a570fd2cc8c7530d45e5 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 19 Jan 2022 21:49:01 +0100 Subject: [PATCH 5/5] Update API dumps Done by running `./gradlew apiDump`. --- core/api/kotlinx-serialization-core.api | 42 +++++++++++++------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/core/api/kotlinx-serialization-core.api b/core/api/kotlinx-serialization-core.api index 9159db4200..4aab661b6f 100644 --- a/core/api/kotlinx-serialization-core.api +++ b/core/api/kotlinx-serialization-core.api @@ -542,13 +542,11 @@ public abstract class kotlinx/serialization/internal/AbstractPolymorphicSerializ public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V } -public final class kotlinx/serialization/internal/ArrayListSerializer : kotlinx/serialization/internal/ListLikeSerializer { +public final class kotlinx/serialization/internal/ArrayListSerializer : kotlinx/serialization/internal/CollectionSerializer { public fun (Lkotlinx/serialization/KSerializer;)V public synthetic fun builder ()Ljava/lang/Object; public synthetic fun builderSize (Ljava/lang/Object;)I public synthetic fun checkCapacity (Ljava/lang/Object;I)V - public synthetic fun collectionIterator (Ljava/lang/Object;)Ljava/util/Iterator; - public synthetic fun collectionSize (Ljava/lang/Object;)I public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; public synthetic fun insert (Ljava/lang/Object;ILjava/lang/Object;)V public synthetic fun toBuilder (Ljava/lang/Object;)Ljava/lang/Object; @@ -624,6 +622,23 @@ public final class kotlinx/serialization/internal/CharSerializer : kotlinx/seria public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V } +public abstract class kotlinx/serialization/internal/CollectionLikeSerializer : kotlinx/serialization/internal/AbstractCollectionSerializer { + public synthetic fun (Lkotlinx/serialization/KSerializer;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public abstract fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + protected abstract fun insert (Ljava/lang/Object;ILjava/lang/Object;)V + protected final fun readAll (Lkotlinx/serialization/encoding/CompositeDecoder;Ljava/lang/Object;II)V + protected fun readElement (Lkotlinx/serialization/encoding/CompositeDecoder;ILjava/lang/Object;Z)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V +} + +public abstract class kotlinx/serialization/internal/CollectionSerializer : kotlinx/serialization/internal/CollectionLikeSerializer { + public fun (Lkotlinx/serialization/KSerializer;)V + public synthetic fun collectionIterator (Ljava/lang/Object;)Ljava/util/Iterator; + protected fun collectionIterator (Ljava/util/Collection;)Ljava/util/Iterator; + public synthetic fun collectionSize (Ljava/lang/Object;)I + protected fun collectionSize (Ljava/util/Collection;)I +} + public final class kotlinx/serialization/internal/DoubleArrayBuilder : kotlinx/serialization/internal/PrimitiveArrayBuilder { public synthetic fun build$kotlinx_serialization_core ()Ljava/lang/Object; } @@ -717,13 +732,11 @@ public final class kotlinx/serialization/internal/HashMapSerializer : kotlinx/se public synthetic fun toResult (Ljava/lang/Object;)Ljava/lang/Object; } -public final class kotlinx/serialization/internal/HashSetSerializer : kotlinx/serialization/internal/ListLikeSerializer { +public final class kotlinx/serialization/internal/HashSetSerializer : kotlinx/serialization/internal/CollectionSerializer { public fun (Lkotlinx/serialization/KSerializer;)V public synthetic fun builder ()Ljava/lang/Object; public synthetic fun builderSize (Ljava/lang/Object;)I public synthetic fun checkCapacity (Ljava/lang/Object;I)V - public synthetic fun collectionIterator (Ljava/lang/Object;)Ljava/util/Iterator; - public synthetic fun collectionSize (Ljava/lang/Object;)I public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; public synthetic fun insert (Ljava/lang/Object;ILjava/lang/Object;)V public synthetic fun toBuilder (Ljava/lang/Object;)Ljava/lang/Object; @@ -788,28 +801,17 @@ public final class kotlinx/serialization/internal/LinkedHashMapSerializer : kotl public synthetic fun toResult (Ljava/lang/Object;)Ljava/lang/Object; } -public final class kotlinx/serialization/internal/LinkedHashSetSerializer : kotlinx/serialization/internal/ListLikeSerializer { +public final class kotlinx/serialization/internal/LinkedHashSetSerializer : kotlinx/serialization/internal/CollectionSerializer { public fun (Lkotlinx/serialization/KSerializer;)V public synthetic fun builder ()Ljava/lang/Object; public synthetic fun builderSize (Ljava/lang/Object;)I public synthetic fun checkCapacity (Ljava/lang/Object;I)V - public synthetic fun collectionIterator (Ljava/lang/Object;)Ljava/util/Iterator; - public synthetic fun collectionSize (Ljava/lang/Object;)I public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; public synthetic fun insert (Ljava/lang/Object;ILjava/lang/Object;)V public synthetic fun toBuilder (Ljava/lang/Object;)Ljava/lang/Object; public synthetic fun toResult (Ljava/lang/Object;)Ljava/lang/Object; } -public abstract class kotlinx/serialization/internal/ListLikeSerializer : kotlinx/serialization/internal/AbstractCollectionSerializer { - public synthetic fun (Lkotlinx/serialization/KSerializer;Lkotlin/jvm/internal/DefaultConstructorMarker;)V - public abstract fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - protected abstract fun insert (Ljava/lang/Object;ILjava/lang/Object;)V - protected final fun readAll (Lkotlinx/serialization/encoding/CompositeDecoder;Ljava/lang/Object;II)V - protected fun readElement (Lkotlinx/serialization/encoding/CompositeDecoder;ILjava/lang/Object;Z)V - public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V -} - public final class kotlinx/serialization/internal/LongArrayBuilder : kotlinx/serialization/internal/PrimitiveArrayBuilder { public synthetic fun build$kotlinx_serialization_core ()Ljava/lang/Object; } @@ -935,7 +937,7 @@ public class kotlinx/serialization/internal/PluginGeneratedSerialDescriptor : ko public abstract class kotlinx/serialization/internal/PrimitiveArrayBuilder { } -public abstract class kotlinx/serialization/internal/PrimitiveArraySerializer : kotlinx/serialization/internal/ListLikeSerializer { +public abstract class kotlinx/serialization/internal/PrimitiveArraySerializer : kotlinx/serialization/internal/CollectionLikeSerializer { public synthetic fun builder ()Ljava/lang/Object; protected final fun builder ()Lkotlinx/serialization/internal/PrimitiveArrayBuilder; public synthetic fun builderSize (Ljava/lang/Object;)I @@ -955,7 +957,7 @@ public abstract class kotlinx/serialization/internal/PrimitiveArraySerializer : protected abstract fun writeContent (Lkotlinx/serialization/encoding/CompositeEncoder;Ljava/lang/Object;I)V } -public final class kotlinx/serialization/internal/ReferenceArraySerializer : kotlinx/serialization/internal/ListLikeSerializer { +public final class kotlinx/serialization/internal/ReferenceArraySerializer : kotlinx/serialization/internal/CollectionLikeSerializer { public fun (Lkotlin/reflect/KClass;Lkotlinx/serialization/KSerializer;)V public synthetic fun builder ()Ljava/lang/Object; public synthetic fun builderSize (Ljava/lang/Object;)I