Fix attachment of children on Vision deserialization

This commit is contained in:
Alexander Nozik 2020-12-06 20:00:34 +03:00
parent a85cd828e6
commit face7bfd0c
8 changed files with 49 additions and 16 deletions

View File

@ -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)
}
}

View File

@ -10,7 +10,6 @@ import hep.dataforge.provider.Type
import hep.dataforge.values.asValue import hep.dataforge.values.asValue
import hep.dataforge.vision.Vision.Companion.TYPE import hep.dataforge.vision.Vision.Companion.TYPE
import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
/** /**
@ -75,8 +74,6 @@ public interface Vision : Configurable, Described {
public const val TYPE: String = "vision" public const val TYPE: String = "vision"
public val STYLE_KEY: Name = "@style".asName() public val STYLE_KEY: Name = "@style".asName()
public fun serializer(): PolymorphicSerializer<Vision> = PolymorphicSerializer(Vision::class)
public val VISIBLE_KEY: Name = "visible".asName() public val VISIBLE_KEY: Name = "visible".asName()
} }
} }

View File

@ -3,6 +3,7 @@ package hep.dataforge.vision
import hep.dataforge.context.* import hep.dataforge.context.*
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.NodeDescriptor
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.modules.SerializersModule 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) { get() = Json(defaultJson) {
serializersModule = this@VisionManager.serializersModule serializersModule = this@VisionManager.serializersModule
} }
public fun decodeFromString(string: String): Vision = jsonFormat.decodeFromString(Vision.serializer(), string) public fun decodeFromString(string: String): Vision = jsonFormat.decodeFromString(visionSerializer, string).also {
public fun encodeToString(vision: Vision): String = jsonFormat.encodeToString(Vision.serializer(), vision) (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 = public fun encodeToJsonElement(vision: Vision): JsonElement =
jsonFormat.encodeToJsonElement(Vision.serializer(), vision) jsonFormat.encodeToJsonElement(visionSerializer, vision)
//TODO remove double transformation with dedicated Meta serial format //TODO remove double transformation with dedicated Meta serial format
public fun decodeFromMeta(meta: Meta, descriptor: NodeDescriptor? = null): Vision = public fun decodeFromMeta(meta: Meta, descriptor: NodeDescriptor? = null): Vision =
@ -67,5 +75,7 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
encodeDefaults = false encodeDefaults = false
ignoreUnknownKeys = true ignoreUnknownKeys = true
} }
internal val visionSerializer: PolymorphicSerializer<Vision> = PolymorphicSerializer(Vision::class)
} }
} }

View File

@ -5,6 +5,7 @@ import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.isEmpty import hep.dataforge.names.isEmpty
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.vision.VisionManager.Companion.visionSerializer
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
@ -54,10 +55,13 @@ public abstract class EmptyVision : Vision {
@SerialName("vision.null") @SerialName("vision.null")
public object NullVision : EmptyVision() public object NullVision : EmptyVision()
/**
* Serialization proxy is used to create immutable reference for a given vision
*/
@Serializable(VisionSerializationProxy.Companion::class) @Serializable(VisionSerializationProxy.Companion::class)
private class VisionSerializationProxy(val ref: Vision) : EmptyVision() { private class VisionSerializationProxy(val ref: Vision) : EmptyVision() {
companion object : KSerializer<VisionSerializationProxy> { companion object : KSerializer<VisionSerializationProxy> {
override val descriptor: SerialDescriptor = Vision.serializer().descriptor override val descriptor: SerialDescriptor = visionSerializer.descriptor
@OptIn(ExperimentalSerializationApi::class) @OptIn(ExperimentalSerializationApi::class)
override fun serialize(encoder: Encoder, value: VisionSerializationProxy) { override fun serialize(encoder: Encoder, value: VisionSerializationProxy) {
@ -67,7 +71,7 @@ private class VisionSerializationProxy(val ref: Vision) : EmptyVision() {
} }
override fun deserialize(decoder: Decoder): VisionSerializationProxy = override fun deserialize(decoder: Decoder): VisionSerializationProxy =
VisionSerializationProxy(Vision.serializer().deserialize(decoder)) VisionSerializationProxy(visionSerializer.deserialize(decoder))
} }
} }

View File

@ -47,14 +47,17 @@ public class VisionClient : AbstractPlugin() {
if (!element.classList.contains(HtmlOutputScope.OUTPUT_CLASS)) error("The element $element is not an output element") if (!element.classList.contains(HtmlOutputScope.OUTPUT_CLASS)) error("The element $element is not an output element")
val endpoint = resolveEndpoint(element) val endpoint = resolveEndpoint(element)
console.info("Vision server is resolved to $endpoint") console.info("Vision server is resolved to $endpoint")
val fetchUrl = URL(endpoint).apply { val fetchUrl = URL(endpoint).apply {
searchParams.append("name", name) searchParams.append("name", name)
pathname += "/vision" pathname += "/vision"
} }
console.info("Fetching vision data from $fetchUrl")
window.fetch(fetchUrl).then { response -> window.fetch(fetchUrl).then { response ->
if (response.ok) { if (response.ok) {
response.text().then { text -> 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") val renderer = findRendererFor(vision) ?: error("Could nof find renderer for $vision")
renderer.render(element, vision) renderer.render(element, vision)
@ -68,7 +71,7 @@ public class VisionClient : AbstractPlugin() {
onmessage = { messageEvent -> onmessage = { messageEvent ->
val stringData: String? = messageEvent.data as? String val stringData: String? = messageEvent.data as? String
if (stringData != null) { if (stringData != null) {
val update = visionManager.jsonFormat.decodeFromString(Vision.serializer(), text) val update = visionManager.decodeFromString(text)
vision.update(update) vision.update(update)
} else { } else {
console.error("WebSocket message data is not a string") console.error("WebSocket message data is not a string")

View File

@ -130,7 +130,7 @@ public class VisionServer internal constructor(
outgoing.send(Frame.Text(json)) outgoing.send(Frame.Text(json))
} }
} catch (ex: Exception) { } 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 //Plots in their json representation

View File

@ -6,6 +6,7 @@ import hep.dataforge.names.Name
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.vision.* import hep.dataforge.vision.*
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.builtins.MapSerializer
@ -126,7 +127,7 @@ internal class Prototypes(
private val mapSerializer: KSerializer<Map<NameToken, Vision>> = private val mapSerializer: KSerializer<Map<NameToken, Vision>> =
MapSerializer( MapSerializer(
NameToken.serializer(), NameToken.serializer(),
Vision.serializer() PolymorphicSerializer(Vision::class)
) )
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor override val descriptor: SerialDescriptor get() = mapSerializer.descriptor

View File

@ -9,6 +9,7 @@ import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.vision.* import hep.dataforge.vision.*
import hep.dataforge.vision.VisionManager.Companion.VISION_SERIALIZER_MODULE_TARGET import hep.dataforge.vision.VisionManager.Companion.VISION_SERIALIZER_MODULE_TARGET
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.PolymorphicModuleBuilder import kotlinx.serialization.modules.PolymorphicModuleBuilder
import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.SerializersModule
@ -64,9 +65,9 @@ public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
serializersModule = serializersModuleForSolids 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){ if(it is VisionGroup){
it.attachChildren() it.attachChildren()
} }