Compatibility for Json top level arrays and nested arrays added.
This commit is contained in:
parent
8c32eaeb6b
commit
58a0584cae
@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Alexander Nozik.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package hep.dataforge.data
|
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.meta.get
|
|
||||||
import hep.dataforge.meta.string
|
|
||||||
|
|
||||||
interface GroupRule {
|
|
||||||
operator fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The class to builder groups of content with annotation defined rules
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
|
||||||
|
|
||||||
object GroupBuilder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create grouping rule that creates groups for different values of value
|
|
||||||
* field with name [key]
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param defaultTagValue
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
fun byValue(key: String, defaultTagValue: String): GroupRule = object :
|
|
||||||
GroupRule {
|
|
||||||
override fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>> {
|
|
||||||
val map = HashMap<String, DataTreeBuilder<T>>()
|
|
||||||
|
|
||||||
node.dataSequence().forEach { (name, data) ->
|
|
||||||
val tagValue = data.meta[key]?.string ?: defaultTagValue
|
|
||||||
map.getOrPut(tagValue) { DataNode.builder(node.type) }[name] = data
|
|
||||||
}
|
|
||||||
|
|
||||||
return map.mapValues { it.value.build() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// @ValueDef(key = "byValue", required = true, info = "The name of annotation value by which grouping should be made")
|
|
||||||
// @ValueDef(
|
|
||||||
// key = "defaultValue",
|
|
||||||
// def = "default",
|
|
||||||
// info = "Default value which should be used for content in which the grouping value is not presented"
|
|
||||||
// )
|
|
||||||
fun byMeta(config: Meta): GroupRule {
|
|
||||||
//TODO expand grouping options
|
|
||||||
return config["byValue"]?.string?.let {
|
|
||||||
byValue(
|
|
||||||
it,
|
|
||||||
config["defaultValue"]?.string ?: "default"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
?: object : GroupRule {
|
|
||||||
override fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>> = mapOf("" to node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Alexander Nozik.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package hep.dataforge.data
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.string
|
||||||
|
|
||||||
|
interface GroupRule {
|
||||||
|
operator fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>>
|
||||||
|
|
||||||
|
companion object{
|
||||||
|
/**
|
||||||
|
* Create grouping rule that creates groups for different values of value
|
||||||
|
* field with name [key]
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param defaultTagValue
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun byValue(key: String, defaultTagValue: String): GroupRule = object :
|
||||||
|
GroupRule {
|
||||||
|
override fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>> {
|
||||||
|
val map = HashMap<String, DataTreeBuilder<T>>()
|
||||||
|
|
||||||
|
node.dataSequence().forEach { (name, data) ->
|
||||||
|
val tagValue = data.meta[key]?.string ?: defaultTagValue
|
||||||
|
map.getOrPut(tagValue) { DataNode.builder(node.type) }[name] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
return map.mapValues { it.value.build() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// @ValueDef(key = "byValue", required = true, info = "The name of annotation value by which grouping should be made")
|
||||||
|
// @ValueDef(
|
||||||
|
// key = "defaultValue",
|
||||||
|
// def = "default",
|
||||||
|
// info = "Default value which should be used for content in which the grouping value is not presented"
|
||||||
|
// )
|
||||||
|
fun byMeta(config: Meta): GroupRule {
|
||||||
|
//TODO expand grouping options
|
||||||
|
return config["byValue"]?.string?.let {
|
||||||
|
byValue(
|
||||||
|
it,
|
||||||
|
config["defaultValue"]?.string ?: "default"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
?: object : GroupRule {
|
||||||
|
override fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>> = mapOf("" to node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,8 @@ object JsonMetaFormat : MetaFormat {
|
|||||||
override val key: Short = 0x4a53//"JS"
|
override val key: Short = 0x4a53//"JS"
|
||||||
|
|
||||||
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) {
|
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) {
|
||||||
val str = meta.toJson().toString()
|
val json = meta.toJson(descriptor)
|
||||||
writeText(str)
|
writeText(json.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
|
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
|
||||||
@ -78,17 +78,46 @@ fun Meta.toJson(descriptor: NodeDescriptor? = null): JsonObject {
|
|||||||
return JsonObject(map)
|
return JsonObject(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun JsonObject.toMeta(descriptor: NodeDescriptor? = null): JsonMeta = JsonMeta(this, descriptor)
|
||||||
|
|
||||||
fun JsonObject.toMeta(descriptor: NodeDescriptor? = null) = JsonMeta(this, descriptor)
|
fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value {
|
||||||
|
return when (this) {
|
||||||
|
JsonNull -> Null
|
||||||
|
else -> this.content.parseValue() // Optimize number and boolean parsing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : MetaBase() {
|
fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMeta> = when (this) {
|
||||||
|
is JsonPrimitive -> {
|
||||||
private fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value {
|
val value = this.toValue(descriptor as? ValueDescriptor)
|
||||||
return when (this) {
|
MetaItem.ValueItem(value)
|
||||||
JsonNull -> Null
|
}
|
||||||
else -> this.content.parseValue() // Optimize number and boolean parsing
|
is JsonObject -> {
|
||||||
|
val meta = toMeta(descriptor as? NodeDescriptor)
|
||||||
|
MetaItem.NodeItem(meta)
|
||||||
|
}
|
||||||
|
is JsonArray -> {
|
||||||
|
if (this.all { it is JsonPrimitive }) {
|
||||||
|
val value = if (isEmpty()) {
|
||||||
|
Null
|
||||||
|
} else {
|
||||||
|
ListValue(
|
||||||
|
map<JsonElement, Value> {
|
||||||
|
//We already checked that all values are primitives
|
||||||
|
(it as JsonPrimitive).toValue(descriptor as? ValueDescriptor)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
MetaItem.ValueItem(value)
|
||||||
|
} else {
|
||||||
|
json {
|
||||||
|
"@value" to this@toMetaItem
|
||||||
|
}.toMetaItem(descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : MetaBase() {
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement): Unit {
|
private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement): Unit {
|
||||||
@ -114,17 +143,7 @@ class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : M
|
|||||||
this[name] = MetaItem.ValueItem(listValue) as MetaItem<JsonMeta>
|
this[name] = MetaItem.ValueItem(listValue) as MetaItem<JsonMeta>
|
||||||
}
|
}
|
||||||
else -> value.forEachIndexed { index, jsonElement ->
|
else -> value.forEachIndexed { index, jsonElement ->
|
||||||
when (jsonElement) {
|
this["$name[$index]"] = jsonElement.toMetaItem(itemDescriptor)
|
||||||
is JsonObject -> {
|
|
||||||
this["$name[$index]"] =
|
|
||||||
MetaItem.NodeItem(jsonElement.toMeta(itemDescriptor as? NodeDescriptor))
|
|
||||||
}
|
|
||||||
is JsonPrimitive -> {
|
|
||||||
this["$name[$index]"] =
|
|
||||||
MetaItem.ValueItem(jsonElement.toValue(itemDescriptor as? ValueDescriptor))
|
|
||||||
}
|
|
||||||
is JsonArray -> TODO("Nested arrays not supported")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ interface MetaFormat : IOFormat<Meta>, Named {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Meta.toString(format: MetaFormat = JsonMetaFormat): String = buildPacket {
|
fun Meta.toString(format: MetaFormat): String = buildPacket {
|
||||||
format.run { writeThis(this@toString) }
|
format.run { writeThis(this@toString) }
|
||||||
}.readText()
|
}.readText()
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package hep.dataforge.io
|
package hep.dataforge.io
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.meta.buildMeta
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
import hep.dataforge.meta.get
|
import kotlinx.serialization.json.json
|
||||||
import hep.dataforge.meta.seal
|
import kotlinx.serialization.json.jsonArray
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -45,4 +45,29 @@ class MetaFormatTest {
|
|||||||
assertEquals<Meta>(meta, result)
|
assertEquals<Meta>(meta, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testJsonToMeta(){
|
||||||
|
val json = jsonArray{
|
||||||
|
//top level array
|
||||||
|
+jsonArray {
|
||||||
|
+JsonPrimitive(88)
|
||||||
|
+json{
|
||||||
|
"c" to "aasdad"
|
||||||
|
"d" to true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+"value"
|
||||||
|
+jsonArray {
|
||||||
|
+JsonPrimitive(1.0)
|
||||||
|
+JsonPrimitive(2.0)
|
||||||
|
+JsonPrimitive(3.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val meta = json.toMetaItem().node!!
|
||||||
|
|
||||||
|
assertEquals(true, meta["@value[0].@value[1].d"].boolean)
|
||||||
|
assertEquals("value", meta["@value[1]"].string)
|
||||||
|
assertEquals(listOf(1.0,2.0,3.0),meta["@value[2"].value?.list?.map{it.number.toDouble()})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user