New Meta serializer

This commit is contained in:
Alexander Nozik 2020-09-16 15:10:43 +03:00
parent 810f79b9ed
commit acfb070938
5 changed files with 56 additions and 47 deletions

View File

@ -27,6 +27,7 @@ class MetaSerializerTest {
@Test @Test
fun testMetaSerialization() { fun testMetaSerialization() {
val string = JSON_PRETTY.encodeToString(MetaSerializer, meta) val string = JSON_PRETTY.encodeToString(MetaSerializer, meta)
println(string)
val restored = JSON_PLAIN.decodeFromString(MetaSerializer, string) val restored = JSON_PLAIN.decodeFromString(MetaSerializer, string)
assertEquals(meta, restored) assertEquals(meta, restored)
} }
@ -35,7 +36,7 @@ class MetaSerializerTest {
@Test @Test
fun testCborSerialization() { fun testCborSerialization() {
val bytes = Cbor.encodeToByteArray(MetaSerializer, meta) val bytes = Cbor.encodeToByteArray(MetaSerializer, meta)
println(bytes.contentToString()) println(bytes.decodeToString())
val restored = Cbor.decodeFromByteArray(MetaSerializer, bytes) val restored = Cbor.decodeFromByteArray(MetaSerializer, bytes)
assertEquals(meta, restored) assertEquals(meta, restored)
} }

View File

@ -28,8 +28,8 @@ public interface ObservableMeta : Meta {
/** /**
* Mutable meta representing object state * Mutable meta representing object state
*/ */
@Serializable @Serializable(Config.Companion::class)
public class Config : AbstractMutableMeta<Config>(), ObservableMeta { public class Config() : AbstractMutableMeta<Config>(), ObservableMeta {
private val listeners = HashSet<MetaListener>() private val listeners = HashSet<MetaListener>()

View File

@ -4,14 +4,11 @@ import hep.dataforge.meta.Meta.Companion.VALUE_KEY
import hep.dataforge.meta.MetaItem.NodeItem import hep.dataforge.meta.MetaItem.NodeItem
import hep.dataforge.meta.MetaItem.ValueItem import hep.dataforge.meta.MetaItem.ValueItem
import hep.dataforge.names.* import hep.dataforge.names.*
import hep.dataforge.values.* import hep.dataforge.values.EnumValue
import kotlinx.serialization.ExperimentalSerializationApi import hep.dataforge.values.Null
import kotlinx.serialization.KSerializer import hep.dataforge.values.Value
import hep.dataforge.values.boolean
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -20,29 +17,17 @@ import kotlinx.serialization.json.Json
* * a [ValueItem] (leaf) * * a [ValueItem] (leaf)
* * a [NodeItem] (node) * * a [NodeItem] (node)
*/ */
@Serializable @Serializable(MetaItemSerializer::class)
public sealed class MetaItem<out M : Meta> { public sealed class MetaItem<out M : Meta>() {
abstract override fun equals(other: Any?): Boolean abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int abstract override fun hashCode(): Int
@Serializable @Serializable(MetaItemSerializer::class)
public class ValueItem(public val value: Value) : MetaItem<Nothing>() { public class ValueItem(public val value: Value) : MetaItem<Nothing>() {
override fun toString(): String = value.toString() override fun toString(): String = value.toString()
@OptIn(ExperimentalSerializationApi::class)
@Serializer(ValueItem::class)
public companion object : KSerializer<ValueItem> {
override val descriptor: SerialDescriptor get() = ValueSerializer.descriptor
override fun deserialize(decoder: Decoder): ValueItem = ValueItem(ValueSerializer.deserialize(decoder))
override fun serialize(encoder: Encoder, value: ValueItem) {
ValueSerializer.serialize(encoder, value.value)
}
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
return this.value == (other as? ValueItem)?.value return this.value == (other as? ValueItem)?.value
} }
@ -52,23 +37,11 @@ public sealed class MetaItem<out M : Meta> {
} }
} }
@Serializable @Serializable(MetaItemSerializer::class)
public class NodeItem<M : Meta>(@Serializable(MetaSerializer::class) public val node: M) : MetaItem<M>() { public class NodeItem<M : Meta>(public val node: M) : MetaItem<M>() {
//Fixing serializer for node could cause class cast problems, but it should not since Meta descendants are not serializeable //Fixing serializer for node could cause class cast problems, but it should not since Meta descendants are not serializeable
override fun toString(): String = node.toString() override fun toString(): String = node.toString()
@OptIn(ExperimentalSerializationApi::class)
@Serializer(NodeItem::class)
public companion object : KSerializer<NodeItem<out Meta>> {
override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor
override fun deserialize(decoder: Decoder): NodeItem<*> = NodeItem(MetaSerializer.deserialize(decoder))
override fun serialize(encoder: Encoder, value: NodeItem<*>) {
MetaSerializer.serialize(encoder, value.node)
}
}
override fun equals(other: Any?): Boolean = node == (other as? NodeItem<*>)?.node override fun equals(other: Any?): Boolean = node == (other as? NodeItem<*>)?.node
override fun hashCode(): Int = node.hashCode() override fun hashCode(): Int = node.hashCode()
@ -112,7 +85,6 @@ public fun interface ItemProvider {
* *
* * Same name siblings are supported via elements with the same [Name] but different queries * * Same name siblings are supported via elements with the same [Name] but different queries
*/ */
@Serializable(MetaSerializer::class)
public interface Meta : MetaRepr, ItemProvider { public interface Meta : MetaRepr, ItemProvider {
/** /**
* Top level items of meta tree * Top level items of meta tree

View File

@ -1,17 +1,54 @@
package hep.dataforge.meta package hep.dataforge.meta
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.values.ValueSerializer
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer import kotlinx.serialization.Serializer
import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.*
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonDecoder import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonEncoder import kotlinx.serialization.json.JsonEncoder
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
@OptIn(ExperimentalSerializationApi::class)
public object MetaItemSerializer : KSerializer<MetaItem<*>> {
@OptIn(InternalSerializationApi::class)
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("hep.dataforge.meta.MetaItem") {
element<Boolean>("isNode")
element("content", buildSerialDescriptor("MetaItem.content", PolymorphicKind.SEALED))
}
override fun deserialize(decoder: Decoder): MetaItem<*> {
decoder.decodeStructure(descriptor) {
//Force strict serialization order
require(decodeElementIndex(descriptor) == 0) { "Node flag must be first item serialized" }
val isNode = decodeBooleanElement(descriptor, 0)
require(decodeElementIndex(descriptor) == 1) { "Missing MetaItem content" }
val item = if (isNode) {
decodeSerializableElement(descriptor,1, MetaSerializer).asMetaItem()
} else {
decodeSerializableElement(descriptor,1,ValueSerializer).asMetaItem()
}
require(decodeElementIndex(descriptor) == CompositeDecoder.DECODE_DONE){"Serialized MetaItem contains additional fields"}
return item
}
}
override fun serialize(encoder: Encoder, value: MetaItem<*>) {
encoder.encodeStructure(descriptor) {
encodeBooleanElement(descriptor, 0, value is MetaItem.NodeItem)
when (value) {
is MetaItem.ValueItem -> encodeSerializableElement(descriptor, 1, ValueSerializer, value.value)
is MetaItem.NodeItem -> encodeSerializableElement(descriptor, 1, MetaSerializer, value.node)
}
}
}
}
/** /**
* Serialized for meta * Serialized for meta
*/ */
@ -19,9 +56,9 @@ import kotlinx.serialization.json.JsonObject
@Serializer(Meta::class) @Serializer(Meta::class)
public object MetaSerializer : KSerializer<Meta> { public object MetaSerializer : KSerializer<Meta> {
private val mapSerializer = MapSerializer( private val mapSerializer: KSerializer<Map<NameToken, MetaItem<Meta>>> = MapSerializer(
NameToken.serializer(), NameToken,
MetaItem.serializer(MetaSerializer) MetaItemSerializer//MetaItem.serializer(MetaSerializer)
) )
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor override val descriptor: SerialDescriptor get() = mapSerializer.descriptor

View File

@ -19,7 +19,6 @@ public enum class ValueType {
* *
* Value can represent a list of value objects. * Value can represent a list of value objects.
*/ */
@Serializable(ValueSerializer::class)
public interface Value { public interface Value {
/** /**
* Get raw value of this value * Get raw value of this value