Add encoding and decoding to/from entity by json encoding/decoding

This commit is contained in:
Atos1337 2021-12-03 23:29:13 +03:00
parent 5da1559882
commit f77f6b7211
5 changed files with 162 additions and 1 deletions

View File

@ -52,5 +52,7 @@ include(
":controls-magix-client", ":controls-magix-client",
":motors", ":motors",
":controls-xodus", ":controls-xodus",
":controls-mongo" ":controls-mongo",
":xodus-serialization"
) )
include("xodus-serialization")

View File

@ -0,0 +1,20 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
`maven-publish`
}
val xodusVersion = "1.3.232"
kscience {
useSerialization {
json()
}
}
dependencies {
implementation(projects.magix.magixApi)
implementation(projects.controlsCore)
implementation("org.jetbrains.xodus:xodus-entity-store:$xodusVersion")
implementation("org.jetbrains.xodus:xodus-environment:$xodusVersion")
implementation("org.jetbrains.xodus:xodus-vfs:$xodusVersion")
}

View File

@ -0,0 +1,42 @@
package ru.mipt.npm.xodus.serialization.json
import jetbrains.exodus.entitystore.Entity
import jetbrains.exodus.entitystore.StoreTransaction
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.json.*
import kotlinx.serialization.serializer
internal fun StoreTransaction.decodeFromEntity(entity: Entity): JsonElement = buildJsonObject {
entity.propertyNames.forEach { property ->
entity.getProperty(property).let { value ->
when (value) {
is Number -> put(property, value)
is Boolean -> put(property, value)
is String -> put(property, value)
else -> throw IllegalStateException("Unsupported type for primitive field")
}
}
}
entity.linkNames.forEach { link ->
entity.getLinks(link).let { entities ->
when (entities.size()) {
1L -> entities.first?.let { put(link, decodeFromEntity(it)) }
else -> {
putJsonArray(link) {
entities.forEach {
add(decodeFromEntity(it))
}
}
}
}
}
}
}
public fun <T> StoreTransaction.decodeFromEntity(entity: Entity, deserializer: DeserializationStrategy<T>): T {
val jsonElement = decodeFromEntity(entity)
return Json.decodeFromJsonElement(deserializer, jsonElement)
}
public inline fun <reified T> StoreTransaction.decodeFromEntity(entity: Entity): T = decodeFromEntity(entity, serializer())

View File

@ -0,0 +1,58 @@
package ru.mipt.npm.xodus.serialization.json
import jetbrains.exodus.entitystore.Entity
import jetbrains.exodus.entitystore.StoreTransaction
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.json.*
import kotlinx.serialization.serializer
internal fun StoreTransaction.encodeToEntity(jsonElement: JsonElement, entity: Entity) {
when (jsonElement) {
is JsonPrimitive -> throw IllegalStateException("Can't serialize primitive value to entity")
is JsonArray -> throw IllegalStateException("Can't serialize array value to entity")
is JsonObject -> {
jsonElement.forEach { entry ->
entry.value.let { value ->
when(value) {
is JsonPrimitive -> {
if (value.isString) {
entity.setProperty(entry.key, value.content)
} else {
(value.longOrNull ?: value.doubleOrNull ?: value.booleanOrNull)?.let {
entity.setProperty(
entry.key,
it
)
}
}
}
// считаем, что все элементы массива - JsonObject, иначе не можем напрямую сериализовать (надо придывать костыли???)
is JsonArray -> {
value.forEach { element ->
val childEntity = newEntity("${entity.type}.${entry.key}")
encodeToEntity(element, childEntity)
entity.addLink(entry.key, childEntity)
}
}
is JsonObject -> {
val childEntity = newEntity("${entity.type}.${entry.key}")
encodeToEntity(value, childEntity)
entity.setLink(entry.key, childEntity)
}
}
}
}
}
}
}
public fun <T> StoreTransaction.encodeToEntity(serializer: SerializationStrategy<T>, value: T, entityType: String): Entity {
val entity: Entity = newEntity(entityType)
encodeToEntity(Json.encodeToJsonElement(serializer, value), entity)
return entity
}
public inline fun <reified T> StoreTransaction.encodeToEntity(value: T, entityType: String): Entity =
encodeToEntity(serializer(), value, entityType)

View File

@ -0,0 +1,39 @@
package ru.mipt.npm.xodus.serialization.json
import jetbrains.exodus.entitystore.PersistentEntityStores
import kotlinx.datetime.Instant
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import ru.mipt.npm.controls.api.PropertyChangedMessage
import ru.mipt.npm.magix.api.MagixMessage
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.Name
import java.nio.file.Paths
internal fun main() {
val expectedMessage = MagixMessage(
"dataforge",
"dataforge",
PropertyChangedMessage(
"acceleration",
Meta {
"x" put 3.0
"y" put 9.0
},
Name.parse("virtual-car"),
Name.parse("magix-virtual-car"),
time = Instant.fromEpochMilliseconds(1337)
),
"magix-virtual-car",
user = JsonObject(content = mapOf(Pair("name", JsonPrimitive("SCADA"))))
)
val entityStore = PersistentEntityStores.newInstance(Paths.get("xodus_serialization").toString())
entityStore.executeInTransaction { txn ->
txn.encodeToEntity(expectedMessage, "MagixMessage")
}
entityStore.executeInTransaction { txn ->
txn.getAll("MagixMessage").first?.let { println(txn.decodeFromEntity<MagixMessage<PropertyChangedMessage>>(it) == expectedMessage) }
}
}