From face7bfd0ce64227e5c278a0d82e685f264e59fc Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 6 Dec 2020 20:00:34 +0300 Subject: [PATCH] Fix attachment of children on Vision deserialization --- .../mipt/npm/sat/GeometrySerializationTest.kt | 17 ++++++++++++++++ .../kotlin/hep/dataforge/vision/Vision.kt | 3 --- .../hep/dataforge/vision/VisionManager.kt | 20 ++++++++++++++----- .../hep/dataforge/vision/visionChange.kt | 8 ++++++-- .../dataforge/vision/client/VisionClient.kt | 7 +++++-- .../dataforge/vision/server/VisionServer.kt | 2 +- .../hep/dataforge/vision/solid/SolidGroup.kt | 3 ++- .../dataforge/vision/solid/SolidManager.kt | 5 +++-- 8 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 demo/sat-demo/src/commonTest/kotlin/ru/mipt/npm/sat/GeometrySerializationTest.kt diff --git a/demo/sat-demo/src/commonTest/kotlin/ru/mipt/npm/sat/GeometrySerializationTest.kt b/demo/sat-demo/src/commonTest/kotlin/ru/mipt/npm/sat/GeometrySerializationTest.kt new file mode 100644 index 00000000..8b9e3c23 --- /dev/null +++ b/demo/sat-demo/src/commonTest/kotlin/ru/mipt/npm/sat/GeometrySerializationTest.kt @@ -0,0 +1,17 @@ +package ru.mipt.npm.sat + +import hep.dataforge.context.Global +import hep.dataforge.vision.solid.SolidManager +import kotlin.test.Test +import kotlin.test.assertEquals + +class GeometrySerializationTest { + @Test + fun testSerialization(){ + val geometry = visionOfSatellite() + val manager = Global.plugins.fetch(SolidManager) + val string = manager.visionManager.encodeToString(geometry) + val reconstructed = manager.visionManager.decodeFromString(string) + assertEquals(geometry.config,reconstructed.config) + } +} \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt index 1ee5036e..51110598 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt @@ -10,7 +10,6 @@ import hep.dataforge.provider.Type import hep.dataforge.values.asValue import hep.dataforge.vision.Vision.Companion.TYPE import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY -import kotlinx.serialization.PolymorphicSerializer import kotlinx.serialization.Transient /** @@ -75,8 +74,6 @@ public interface Vision : Configurable, Described { public const val TYPE: String = "vision" public val STYLE_KEY: Name = "@style".asName() - public fun serializer(): PolymorphicSerializer = PolymorphicSerializer(Vision::class) - public val VISIBLE_KEY: Name = "visible".asName() } } diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionManager.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionManager.kt index 7c0e14f6..ffb26ccf 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionManager.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionManager.kt @@ -3,6 +3,7 @@ package hep.dataforge.vision import hep.dataforge.context.* import hep.dataforge.meta.* import hep.dataforge.meta.descriptors.NodeDescriptor +import kotlinx.serialization.PolymorphicSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.modules.SerializersModule @@ -24,17 +25,24 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) { } } - public val jsonFormat: Json + private val jsonFormat: Json get() = Json(defaultJson) { serializersModule = this@VisionManager.serializersModule } - public fun decodeFromString(string: String): Vision = jsonFormat.decodeFromString(Vision.serializer(), string) - public fun encodeToString(vision: Vision): String = jsonFormat.encodeToString(Vision.serializer(), vision) + public fun decodeFromString(string: String): Vision = jsonFormat.decodeFromString(visionSerializer, string).also { + (it as? VisionGroup)?.attachChildren() + } + + public fun encodeToString(vision: Vision): String = jsonFormat.encodeToString(visionSerializer, vision) + + public fun decodeFromJson(json: JsonElement): Vision = + jsonFormat.decodeFromJsonElement(visionSerializer, json).also { + (it as? VisionGroup)?.attachChildren() + } - public fun decodeFromJson(json: JsonElement): Vision = jsonFormat.decodeFromJsonElement(Vision.serializer(), json) public fun encodeToJsonElement(vision: Vision): JsonElement = - jsonFormat.encodeToJsonElement(Vision.serializer(), vision) + jsonFormat.encodeToJsonElement(visionSerializer, vision) //TODO remove double transformation with dedicated Meta serial format public fun decodeFromMeta(meta: Meta, descriptor: NodeDescriptor? = null): Vision = @@ -67,5 +75,7 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) { encodeDefaults = false ignoreUnknownKeys = true } + + internal val visionSerializer: PolymorphicSerializer = PolymorphicSerializer(Vision::class) } } \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/visionChange.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/visionChange.kt index e0041bf5..76bd6775 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/visionChange.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/visionChange.kt @@ -5,6 +5,7 @@ import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.names.Name import hep.dataforge.names.isEmpty import hep.dataforge.names.plus +import hep.dataforge.vision.VisionManager.Companion.visionSerializer import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow @@ -54,10 +55,13 @@ public abstract class EmptyVision : Vision { @SerialName("vision.null") public object NullVision : EmptyVision() +/** + * Serialization proxy is used to create immutable reference for a given vision + */ @Serializable(VisionSerializationProxy.Companion::class) private class VisionSerializationProxy(val ref: Vision) : EmptyVision() { companion object : KSerializer { - override val descriptor: SerialDescriptor = Vision.serializer().descriptor + override val descriptor: SerialDescriptor = visionSerializer.descriptor @OptIn(ExperimentalSerializationApi::class) override fun serialize(encoder: Encoder, value: VisionSerializationProxy) { @@ -67,7 +71,7 @@ private class VisionSerializationProxy(val ref: Vision) : EmptyVision() { } override fun deserialize(decoder: Decoder): VisionSerializationProxy = - VisionSerializationProxy(Vision.serializer().deserialize(decoder)) + VisionSerializationProxy(visionSerializer.deserialize(decoder)) } } diff --git a/visionforge-core/src/jsMain/kotlin/hep/dataforge/vision/client/VisionClient.kt b/visionforge-core/src/jsMain/kotlin/hep/dataforge/vision/client/VisionClient.kt index ce74f85f..d689e66f 100644 --- a/visionforge-core/src/jsMain/kotlin/hep/dataforge/vision/client/VisionClient.kt +++ b/visionforge-core/src/jsMain/kotlin/hep/dataforge/vision/client/VisionClient.kt @@ -47,14 +47,17 @@ public class VisionClient : AbstractPlugin() { if (!element.classList.contains(HtmlOutputScope.OUTPUT_CLASS)) error("The element $element is not an output element") val endpoint = resolveEndpoint(element) console.info("Vision server is resolved to $endpoint") + val fetchUrl = URL(endpoint).apply { searchParams.append("name", name) pathname += "/vision" } + + console.info("Fetching vision data from $fetchUrl") window.fetch(fetchUrl).then { response -> if (response.ok) { response.text().then { text -> - val vision = visionManager.jsonFormat.decodeFromString(Vision.serializer(), text) + val vision = visionManager.decodeFromString(text) val renderer = findRendererFor(vision) ?: error("Could nof find renderer for $vision") renderer.render(element, vision) @@ -68,7 +71,7 @@ public class VisionClient : AbstractPlugin() { onmessage = { messageEvent -> val stringData: String? = messageEvent.data as? String if (stringData != null) { - val update = visionManager.jsonFormat.decodeFromString(Vision.serializer(), text) + val update = visionManager.decodeFromString(text) vision.update(update) } else { console.error("WebSocket message data is not a string") diff --git a/visionforge-server/src/main/kotlin/hep/dataforge/vision/server/VisionServer.kt b/visionforge-server/src/main/kotlin/hep/dataforge/vision/server/VisionServer.kt index c306fae4..8b53dc90 100644 --- a/visionforge-server/src/main/kotlin/hep/dataforge/vision/server/VisionServer.kt +++ b/visionforge-server/src/main/kotlin/hep/dataforge/vision/server/VisionServer.kt @@ -130,7 +130,7 @@ public class VisionServer internal constructor( outgoing.send(Frame.Text(json)) } } catch (ex: Exception) { - application.log.debug("Closed server socket for $name") + application.log.debug("Closed server socket for $name with exception $ex") } } //Plots in their json representation diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt index 991fc09b..50b53cdc 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt @@ -6,6 +6,7 @@ import hep.dataforge.names.Name import hep.dataforge.names.NameToken import hep.dataforge.vision.* import kotlinx.serialization.KSerializer +import kotlinx.serialization.PolymorphicSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.MapSerializer @@ -126,7 +127,7 @@ internal class Prototypes( private val mapSerializer: KSerializer> = MapSerializer( NameToken.serializer(), - Vision.serializer() + PolymorphicSerializer(Vision::class) ) override val descriptor: SerialDescriptor get() = mapSerializer.descriptor diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidManager.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidManager.kt index 34bfed6b..d098a72b 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidManager.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidManager.kt @@ -9,6 +9,7 @@ import hep.dataforge.names.Name import hep.dataforge.names.toName import hep.dataforge.vision.* import hep.dataforge.vision.VisionManager.Companion.VISION_SERIALIZER_MODULE_TARGET +import kotlinx.serialization.PolymorphicSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.modules.PolymorphicModuleBuilder import kotlinx.serialization.modules.SerializersModule @@ -64,9 +65,9 @@ public class SolidManager(meta: Meta) : AbstractPlugin(meta) { serializersModule = serializersModuleForSolids } - public fun encodeToString(solid: Solid): String = jsonForSolids.encodeToString(Vision.serializer(), solid) + internal fun encodeToString(solid: Solid): String = jsonForSolids.encodeToString(PolymorphicSerializer(Vision::class), solid) - public fun decodeFromString(str: String): Vision = jsonForSolids.decodeFromString(Vision.serializer(), str).also { + internal fun decodeFromString(str: String): Vision = jsonForSolids.decodeFromString(PolymorphicSerializer(Vision::class), str).also { if(it is VisionGroup){ it.attachChildren() }