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

View File

@ -28,8 +28,8 @@ public interface ObservableMeta : Meta {
/**
* Mutable meta representing object state
*/
@Serializable
public class Config : AbstractMutableMeta<Config>(), ObservableMeta {
@Serializable(Config.Companion::class)
public class Config() : AbstractMutableMeta<Config>(), ObservableMeta {
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.ValueItem
import hep.dataforge.names.*
import hep.dataforge.values.*
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import hep.dataforge.values.EnumValue
import hep.dataforge.values.Null
import hep.dataforge.values.Value
import hep.dataforge.values.boolean
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
@ -20,29 +17,17 @@ import kotlinx.serialization.json.Json
* * a [ValueItem] (leaf)
* * a [NodeItem] (node)
*/
@Serializable
public sealed class MetaItem<out M : Meta> {
@Serializable(MetaItemSerializer::class)
public sealed class MetaItem<out M : Meta>() {
abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int
@Serializable
@Serializable(MetaItemSerializer::class)
public class ValueItem(public val value: Value) : MetaItem<Nothing>() {
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 {
return this.value == (other as? ValueItem)?.value
}
@ -52,23 +37,11 @@ public sealed class MetaItem<out M : Meta> {
}
}
@Serializable
public class NodeItem<M : Meta>(@Serializable(MetaSerializer::class) public val node: M) : MetaItem<M>() {
@Serializable(MetaItemSerializer::class)
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
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 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
*/
@Serializable(MetaSerializer::class)
public interface Meta : MetaRepr, ItemProvider {
/**
* Top level items of meta tree

View File

@ -1,17 +1,54 @@
package hep.dataforge.meta
import hep.dataforge.names.NameToken
import hep.dataforge.values.ValueSerializer
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonEncoder
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
*/
@ -19,9 +56,9 @@ import kotlinx.serialization.json.JsonObject
@Serializer(Meta::class)
public object MetaSerializer : KSerializer<Meta> {
private val mapSerializer = MapSerializer(
NameToken.serializer(),
MetaItem.serializer(MetaSerializer)
private val mapSerializer: KSerializer<Map<NameToken, MetaItem<Meta>>> = MapSerializer(
NameToken,
MetaItemSerializer//MetaItem.serializer(MetaSerializer)
)
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.
*/
@Serializable(ValueSerializer::class)
public interface Value {
/**
* Get raw value of this value