From 03e4679ff4f187770a5bc1fc454d42ad202751d8 Mon Sep 17 00:00:00 2001 From: Gk0Wk Date: Tue, 4 Jul 2023 16:23:49 +0800 Subject: [PATCH] feature: version to 2.0.8 --- .idea/vcs.xml | 6 + README.md | 2 +- build.gradle.kts | 4 +- docs/config.md | 101 +++++++++++++ settings.gradle.kts | 4 +- .../newnan/violet/config/ConfigManager2.kt | 143 +++++++++--------- .../violet/config/JsonObjectExtension.kt | 87 +++++++++++ .../kotlin/city/newnan/violet/json/Util.kt | 62 -------- src/test/kotlin/Main.kt | 28 +++- 9 files changed, 290 insertions(+), 147 deletions(-) create mode 100644 .idea/vcs.xml create mode 100644 docs/config.md create mode 100644 src/main/kotlin/city/newnan/violet/config/JsonObjectExtension.kt delete mode 100755 src/main/kotlin/city/newnan/violet/json/Util.kt diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 68f53c5..68e6764 100755 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Useful toolkits java library for Bukkit Server Plugin. -- [x] ConfigManager (JSON, YAML, TOML, HOCON, Properties) +- [x] [ConfigManager](./docs/config.md) (JSON, YAML, TOML, HOCON, Properties, XML, CSV) - [x] MessageManager (i18n Supported) - [x] LanguageManager - [x] CommandManager (Deprecated, and recommend to use [aikar's commands](https://github.com/aikar/commands)) diff --git a/build.gradle.kts b/build.gradle.kts index 5d79da5..bc4d335 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -41,9 +41,6 @@ dependencies { api("org.ktorm:ktorm-core:3.6.0") // Network api("com.squareup.okhttp3:okhttp:5.0.0-alpha.11") - // JSON - api("com.lectra:koson:1.2.5") - api("com.google.code.gson:gson:2.10.1") // JDK api("org.jetbrains.kotlin:kotlin-stdlib:1.8.21") // ConfigureFile @@ -56,6 +53,7 @@ dependencies { api("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.15.2") api("com.fasterxml.jackson.dataformat:jackson-dataformat-properties:2.15.2") api("com.jasonclawson:jackson-dataformat-hocon:1.1.0") + api("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.2") // Test testImplementation(kotlin("test")) } diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 0000000..8490f24 --- /dev/null +++ b/docs/config.md @@ -0,0 +1,101 @@ +# ConfigManager + +> ConfigManager2 is based on jackson. + +Support: + +* JSON, YAML, TOML, HOCON, Properties, XML, CSV. +* Tree-mode & Class-mapping-mode. +* Bukkit's ConfigurationSerializable like ItemStack, ItemMeta, Location, etc.. + +Setup: + +```kotlin +// In plugin onLoad +val configManager = ConfigManager2(this) +``` + +Read config: + +```kotlin +// Check if config exists +configManager.touch("config.yml") +// Get config +val config = configManager["config.yml"] +// Visit config +config.root { + // it == ObjectNode of jackson + val enableMultiHome = it["multi-home", "enable"].asBoolean() + val homeLimit = it["multi-home", "limit"].asInt(1) // can set default value + val inventory = it["inventory"].asBase64Inventory() + val location = it["location"].asConfigurationSerializable() +} +``` + +Write: + +```kotlin +// Write and save +configManager["store.json"].save { + it.set("last-update", System.currentTimeMillis()) + it.set("last-player", Bukkit.getOfflinePlayers()[0]) + it.set("example-item", ItemStack(Material.APPLE, 64)) + it.setBase64("example-inventory", Bukkit.getOfflinePlayers()[0].player!!.inventory) + it.remove("foo") +} +``` + +Multi-type support: + +```kotlin +// Convert type +configManager["1.json"].saveAs("1.xml") +``` + +## About ObjectNode + +Further reading: + +- [Jackson Document](https://github.com/FasterXML/jackson-docs) +- [Databind annotations for class](https://stackabuse.com/definitive-guide-to-jackson-objectmapper-serialize-and-deserialize-java-objects/) + +locate a noe: + +```kotlin +node["123", "456", 12, "a"].asText() +node get "123".asInt() +``` + +read value: + +```kotlin +node.asInt() / asText() / asBoolean() / ... +node.asList() // ArrayList +node.asMap() // LinkedHashMap +node.asUUID() // to UUID +node.asMaterial() // to Bukkit Material +node.asType() // to your class +node.asConfigurationSerializable() // to Bukkit ConfigurationSerializable +node.asBase64Inventory() / asBase64ItemStacks() / asBase64ItemStack() +``` + +write value: + +```kotlin +node.put("key", 1 / "123" / true / ...) +node.put("key", listOf(1, 2, 3)) +node.put("key", mapOf("a" to 1, "b" to 2)) +node.put("key", YourClass()) +node.put("key", ItemStack(Material.APPLE, 1)) +node.putBase64("key", Inventory / ItemStack / Array) +``` + +## Reference + +- [Jackson Core](https://github.com/FasterXML/jackson-core) +- [Jackson Databind](https://github.com/FasterXML/jackson-databind) +- [Jackson YAML](https://github.com/FasterXML/jackson-dataformats-text/tree/master/yaml) +- [Jackson XML](https://github.com/FasterXML/jackson-dataformat-xml) +- [Jackson CSV](https://github.com/FasterXML/jackson-dataformats-text/tree/master/csv) +- [Jackson Properties](https://github.com/FasterXML/jackson-dataformats-text/tree/master/properties) +- [Jackson TOML](https://github.com/FasterXML/jackson-dataformats-text/tree/2.13/toml) diff --git a/settings.gradle.kts b/settings.gradle.kts index 366a002..6febf1b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1 @@ - -rootProject.name = "Violet" - +rootProject.name = "Violet" \ No newline at end of file diff --git a/src/main/kotlin/city/newnan/violet/config/ConfigManager2.kt b/src/main/kotlin/city/newnan/violet/config/ConfigManager2.kt index cb62f8b..8ab74fa 100644 --- a/src/main/kotlin/city/newnan/violet/config/ConfigManager2.kt +++ b/src/main/kotlin/city/newnan/violet/config/ConfigManager2.kt @@ -2,7 +2,7 @@ package city.newnan.violet.config -import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.databind.node.ObjectNode @@ -11,76 +11,34 @@ import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper import com.fasterxml.jackson.dataformat.toml.TomlMapper import com.fasterxml.jackson.dataformat.xml.XmlMapper import com.fasterxml.jackson.dataformat.yaml.YAMLMapper +import com.fasterxml.jackson.module.kotlin.registerKotlinModule import com.jasonclawson.jackson.dataformat.hocon.HoconFactory import me.lucko.helper.Schedulers import me.lucko.helper.scheduler.Task import me.lucko.helper.terminable.Terminable import me.lucko.helper.terminable.TerminableConsumer -import org.bukkit.Bukkit -import org.bukkit.Material -import org.bukkit.OfflinePlayer import org.bukkit.plugin.Plugin import java.io.* -import java.util.* import kotlin.collections.HashMap -/** - * 使用索引器路径获取节点 - * - * ``` - * val node1 = node["foo", 2, "bar"] - * ``` - * - * @receiver [ObjectNode] - * @param paths Paths 字符串或整数,分别用于索引Object和Array - * @return [ObjectNode] - * @throws Exception 未知路径类型 - */ -operator fun ObjectNode.get(vararg paths: Any): ObjectNode { - var node: ObjectNode = this - for (path in paths) { - node = when (path) { - is String -> node[path] as ObjectNode - is Int -> node[path] as ObjectNode - else -> throw Exception("Unknown path type: ${path::class.java} (value: $path)") - } - } - return node -} - -infix fun ObjectNode.get(key: String) = get(key) as ObjectNode - -fun ObjectNode.asType(): T = ConfigManager2.mapper[ConfigManager2.ConfigFileType.Json] - .convertValue(this, object : com.fasterxml.jackson.core.type.TypeReference() {}) -fun ObjectNode.asMap() = asType>() -fun Map<*, *>.toObjectNode(): ObjectNode = ConfigManager2.mapper[ConfigManager2.ConfigFileType.Json] - .valueToTree(this) -fun ObjectNode.asList() = asType>() -fun List<*>.toObjectNode(): ObjectNode = ConfigManager2.mapper[ConfigManager2.ConfigFileType.Json] - .valueToTree(this) -fun T.asObjectNode(): ObjectNode = ConfigManager2.mapper[ConfigManager2.ConfigFileType.Json] - .valueToTree(this) -fun JsonNode.asUUID(): UUID = UUID.fromString(asText()) -fun ObjectNode.put(key: String, value: UUID): ObjectNode = put(key, value.toString()) -fun JsonNode.asPlayer(): OfflinePlayer = Bukkit.getOfflinePlayer(asUUID()) -fun ObjectNode.put(key: String, value: OfflinePlayer): ObjectNode = put(key, value.uniqueId.toString()) -fun JsonNode.asMaterial(): Material? = Material.matchMaterial(asText()) -fun ObjectNode.put(key: String, value: Material): ObjectNode = put(key, value.key.toString()) /** * 配置文件对象 * - * @param plugin 插件实例 - * @param dataFolder 配置文件目录 - * @param mapper Jackson mapper + * @property type 类型 + * @property manager 配置管理器实例 + * @constructor Create [Configure2] + * + * @param path 配置文件路径 + * @param node 配置文件的根节点 */ class Configure2( - rawPath: File, + path: File?, /** * 配置文件类型 */ var type: ConfigManager2.ConfigFileType, - nodeInit: ObjectNode, + node: ObjectNode, /** * 配置文件绑定的ConfigManager2 */ @@ -92,9 +50,10 @@ class Configure2( * 配置文件启用或关闭持久化保存,即不会因为长久未访问就从内存中卸载,适合经常访问的配置文件。 */ fun setCache(enable: Boolean) { + if (path == null) return if (enable == _enableCache) return _enableCache = enable - val p = path.canonicalPath + val p = path!!.canonicalPath if (enable) { manager.configCache[p] = this manager.configTimestampMap[p] = System.currentTimeMillis() @@ -125,9 +84,10 @@ class Configure2( * @param enable 是否启动持久化 */ fun setPersistence(enable: Boolean) { + if (path == null) return if (enable == _enablePersistence) return _enablePersistence = enable - if (enable) manager.persistentConfigSet.add(path.canonicalPath) + if (enable) manager.persistentConfigSet.add(path!!.canonicalPath) } /** * 将某个文件设置为持久化保存的,即不会因为长久未访问就从内存中卸载;或者取消。以缓存为前提。 @@ -139,12 +99,12 @@ class Configure2( /** * 配置文件路径 */ - var path: File = rawPath.canonicalFile + var path: File? = path?.canonicalFile /** * 配置文件的Jackson根节点 */ - var node = nodeInit + var node = node private set /** @@ -191,32 +151,33 @@ class Configure2( */ @Throws(ConfigManager2.UnknownConfigFileFormatException::class, IOException::class) fun save() { + if (path == null) return val mapper: ObjectMapper try { mapper = ConfigManager2.mapper[type] } catch (e: Exception) { - throw ConfigManager2.UnknownConfigFileFormatException(path.canonicalPath) + throw ConfigManager2.UnknownConfigFileFormatException(path!!.canonicalPath) } - val writer = BufferedWriter(FileWriter(path)) + val writer = BufferedWriter(FileWriter(path!!)) mapper.writeValue(writer, node) writer.close() if (_enableCache) { - manager.configTimestampMap[path.canonicalPath] = System.currentTimeMillis() + manager.configTimestampMap[path!!.canonicalPath] = System.currentTimeMillis() } } /** * 克隆一个新的配置文件 - * @param file 要保存的文件 + * @param file 要保存的文件,注意路径是相对于插件数据目录的 * @param type 配置文件类型 * @return 新的配置文件实例 */ fun clone(file: String, type: ConfigManager2.ConfigFileType? = null): Configure2 - = clone(File(file), type) + = clone(File(manager.plugin.dataFolder, file), type) /** * 克隆一个新的配置文件 - * @param file 要保存的文件 + * @param file 要保存的文件,不是相对于插件数据目录的 * @param type 配置文件类型 * @return 新的配置文件实例 */ @@ -225,7 +186,7 @@ class Configure2( /** * 保存为另一个文件 - * @param file 要保存的文件 + * @param file 要保存的文件,不是相对于插件数据目录的 * @param clone 是否克隆一个新的配置文件 * @param type 配置文件类型 * @return 新的配置文件实例 @@ -242,13 +203,13 @@ class Configure2( /** * 保存为另一个文件 - * @param file 要保存的文件 + * @param file 要保存的文件,注意路径是相对于插件数据目录的 * @param clone 是否克隆一个新的配置文件 * @param type 配置文件类型 * @return 新的配置文件实例 */ fun saveAs(file: String, clone: Boolean = true, type: ConfigManager2.ConfigFileType? = null): Configure2 - = saveAs(File(file), clone, type) + = saveAs(File(manager.plugin.dataFolder, file), clone, type) /** * 保存为另一个文件 @@ -280,14 +241,25 @@ class Configure2( */ inline fun saveAs(file: String, clone: Boolean = true, type: ConfigManager2.ConfigFileType? = null, block: (ObjectNode) -> Unit): Configure2 - = saveAs(File(file), clone, type, block) + = saveAs(File(manager.plugin.dataFolder, file), clone, type, block) /** * 删除配置文件 */ fun remove() { + if (path == null) return unload() - path.delete() + path!!.delete() + } + + /** + * 转换为字符串 + * + * @param type Type 类型 + * @return + */ + fun toString(type: ConfigManager2.ConfigFileType = this.type): String { + return ConfigManager2.mapper[type].writeValueAsString(node) } } @@ -299,19 +271,29 @@ class ConfigManager2 /** * 绑定的插件实例 */ - private val plugin: Plugin + val plugin: Plugin ) : Terminable { companion object { private val MapperBuilders = hashMapOf( - ConfigFileType.Json to { ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT) }, - ConfigFileType.Yaml to { YAMLMapper().enable(SerializationFeature.INDENT_OUTPUT) }, - ConfigFileType.Toml to { TomlMapper().enable(SerializationFeature.INDENT_OUTPUT) }, - ConfigFileType.Properties to { JavaPropsMapper().enable(SerializationFeature.INDENT_OUTPUT) }, - ConfigFileType.Csv to { CsvMapper().enable(SerializationFeature.INDENT_OUTPUT) }, - ConfigFileType.Xml to { XmlMapper().enable(SerializationFeature.INDENT_OUTPUT) }, - ConfigFileType.Hocon to { ObjectMapper(HoconFactory()).enable(SerializationFeature.INDENT_OUTPUT) } + ConfigFileType.Json to { decorateMapper(ObjectMapper()) }, + ConfigFileType.Yaml to { decorateMapper(YAMLMapper()) }, + ConfigFileType.Toml to { decorateMapper(TomlMapper()) }, + ConfigFileType.Properties to { decorateMapper(JavaPropsMapper()) }, + ConfigFileType.Csv to { decorateMapper(CsvMapper()) }, + ConfigFileType.Xml to { decorateMapper(XmlMapper()) }, + ConfigFileType.Hocon to { decorateMapper(ObjectMapper(HoconFactory())) } ) private val Mappers = HashMap() + private fun decorateMapper(mapper: ObjectMapper): ObjectMapper { + // 序列化时使用缩进 + mapper.configure(SerializationFeature.INDENT_OUTPUT, true) + // 解析时忽略未知的属性 + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + // 支持 Kotlin 类 + // https://github.com/FasterXML/jackson-module-kotlin + mapper.registerKotlinModule() + return mapper + } /** * 获取一个 mapper @@ -568,6 +550,17 @@ class ConfigManager2 persistentConfigSet.clear() } + /** + * 从文本中加载配置文件 + * @param text 文本 + * @param type 配置文件类型 + * @return 配置文件实例 + */ + fun parseText(text: String, type: ConfigFileType): Configure2 { + val node = mapper[type].readTree(text) as ObjectNode + return Configure2(null, type, node, this) + } + /** * 未知的配置文件格式异常 */ diff --git a/src/main/kotlin/city/newnan/violet/config/JsonObjectExtension.kt b/src/main/kotlin/city/newnan/violet/config/JsonObjectExtension.kt new file mode 100644 index 0000000..8c50854 --- /dev/null +++ b/src/main/kotlin/city/newnan/violet/config/JsonObjectExtension.kt @@ -0,0 +1,87 @@ +@file:Suppress("unused") + +package city.newnan.violet.config + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.node.ObjectNode +import me.lucko.helper.serialize.InventorySerialization +import org.bukkit.Material +import org.bukkit.configuration.serialization.ConfigurationSerializable +import org.bukkit.configuration.serialization.ConfigurationSerialization +import org.bukkit.inventory.Inventory +import org.bukkit.inventory.ItemStack +import java.util.UUID + + +/** + * 使用索引器路径获取节点 + * + * ``` + * val node1 = node["foo", 2, "bar"] + * ``` + * + * @receiver [ObjectNode] + * @param paths Paths 字符串或整数,分别用于索引Object和Array + * @return [ObjectNode] + * @throws Exception 未知路径类型 + */ +operator fun ObjectNode.get(vararg paths: Any): ObjectNode { + var node: ObjectNode = this + for (path in paths) { + node = when (path) { + is String -> node[path] as ObjectNode + is Int -> node[path] as ObjectNode + else -> throw Exception("Unknown path type: ${path::class.java} (value: $path)") + } + } + return node +} + +infix fun ObjectNode.get(key: String) = get(key) as ObjectNode + +fun JsonNode.asType(): T = ConfigManager2.mapper[ConfigManager2.ConfigFileType.Json] + .convertValue(this, object : com.fasterxml.jackson.core.type.TypeReference() {}) +fun JsonNode.asMap() = asType>() +fun Map<*, *>.toObjectNode(): ObjectNode = ConfigManager2.mapper[ConfigManager2.ConfigFileType.Json] + .valueToTree(this) +fun ObjectNode.put(key: String, value: Map<*, *>) { + replace(key, value.toObjectNode()) +} +fun JsonNode.asList() = asType>() +fun List<*>.toObjectNode(): ObjectNode = ConfigManager2.mapper[ConfigManager2.ConfigFileType.Json] + .valueToTree(this) +fun ObjectNode.put(key: String, value: List<*>) { + replace(key, value.toObjectNode()) +} +fun T.toObjectNode(): ObjectNode = ConfigManager2.mapper[ConfigManager2.ConfigFileType.Json] + .valueToTree(this) +fun ObjectNode.put(key: String, value: T) { + replace(key, value.toObjectNode()) +} +fun JsonNode.asUUID(): UUID = UUID.fromString(asText()) +fun ObjectNode.put(key: String, value: UUID): ObjectNode = put(key, value.toString()) +fun JsonNode.asMaterial(): Material? = Material.matchMaterial(asText()) +fun ObjectNode.put(key: String, value: Material): ObjectNode = put(key, value.key.toString()) +fun ObjectNode.put(key: String, value: ConfigurationSerializable): ObjectNode + = replace(key, + ConfigManager2.mapper[ConfigManager2.ConfigFileType.Json].valueToTree(value.serialize())) as ObjectNode +fun JsonNode.asConfigurationSerializable(): T? + = ConfigurationSerialization.deserializeObject(asMap()) as T? +fun JsonNode.asBase64Inventory(): Inventory { + val map = asMap() + return InventorySerialization.decodeInventory(map["data"] as String, map["title"] as String) +} +fun JsonNode.asBase64ItemStacks(): Array + = InventorySerialization.decodeItemStacks(asText()) +fun JsonNode.asBase64ItemStack(): ItemStack + = InventorySerialization.decodeItemStack(asText()) +fun ObjectNode.putBase64(key: String, value: Inventory, title: String): ObjectNode + = replace(key, linkedMapOf( + "title" to title, + "data" to InventorySerialization.encodeInventory(value) + ).toObjectNode()) as ObjectNode + +fun ObjectNode.putBase64(key: String, value: Array): ObjectNode + = put(key, InventorySerialization.encodeItemStacks(value)) +fun ObjectNode.putBase64(key: String, value: ItemStack): ObjectNode + = put(key, InventorySerialization.encodeItemStack(value)) \ No newline at end of file diff --git a/src/main/kotlin/city/newnan/violet/json/Util.kt b/src/main/kotlin/city/newnan/violet/json/Util.kt deleted file mode 100755 index d6aaf5d..0000000 --- a/src/main/kotlin/city/newnan/violet/json/Util.kt +++ /dev/null @@ -1,62 +0,0 @@ -package city.newnan.violet.json - -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import com.google.gson.JsonPrimitive -import java.math.BigDecimal -import java.math.BigInteger - -fun JsonObject.hasJsonObject(key: String): Boolean = has(key) && get(key).isJsonObject -fun JsonObject.hasJsonArray(key: String): Boolean = has(key) && get(key).isJsonArray -fun JsonObject.hasJsonNull(key: String): Boolean = has(key) && get(key).isJsonNull -fun JsonObject.hasJsonPrimitive(key: String): Boolean = has(key) && get(key).isJsonPrimitive - - -fun JsonObject.getElement(vararg keyPath: String): JsonElement? { - if (keyPath.isEmpty()) - return this - var currentNode: JsonObject = this - for (i: Int in 0 until keyPath.size - 1) { - val key = keyPath[i] - if (!hasJsonObject(key)) - return null - currentNode = currentNode.getAsJsonObject(key) - } - return currentNode.get(keyPath.last()) -} -// -fun JsonObject.getJsonObject(defaultValue: JsonObject?, vararg keyPath: String): JsonObject? = - getElement(*keyPath).run { if ((this == null) || !isJsonObject) defaultValue else asJsonObject } -fun JsonObject.getJsonArray(defaultValue: JsonArray?, vararg keyPath: String): JsonArray? = - getElement(*keyPath).run { if ((this == null) || !isJsonArray) defaultValue else asJsonArray } -fun JsonObject.getJsonPrimitive(vararg keyPath: String): JsonPrimitive? = - getElement(*keyPath).run { if ((this == null) || !isJsonPrimitive) null else asJsonPrimitive } -// Integer -fun JsonObject.getLong(defaultValue: Long?, vararg keyPath: String): Long? = - getJsonPrimitive(*keyPath).run { this?.asLong ?: defaultValue } -fun JsonObject.getInt(defaultValue: Int?, vararg keyPath: String): Int? = - getJsonPrimitive(*keyPath).run { this?.asInt ?: defaultValue } -fun JsonObject.getShort(defaultValue: Short?, vararg keyPath: String): Short? = - getJsonPrimitive(*keyPath).run { this?.asShort ?: defaultValue } -fun JsonObject.getByte(defaultValue: Byte?, vararg keyPath: String): Byte? = - getJsonPrimitive(*keyPath).run { this?.asByte ?: defaultValue } -fun JsonObject.getBigInteger(defaultValue: BigInteger?, vararg keyPath: String): BigInteger? = - getJsonPrimitive(*keyPath).run { this?.asBigInteger ?: defaultValue } -// Real -fun JsonObject.getDouble(defaultValue: Double?, vararg keyPath: String): Double? = - getJsonPrimitive(*keyPath).run { this?.asDouble ?: defaultValue } -fun JsonObject.getFloat(defaultValue: Float?, vararg keyPath: String): Float? = - getJsonPrimitive(*keyPath).run { this?.asFloat ?: defaultValue } -fun JsonObject.getBigDecimal(defaultValue: BigDecimal?, vararg keyPath: String): BigDecimal? = - getJsonPrimitive(*keyPath).run { this?.asBigDecimal ?: defaultValue } -// String -fun JsonObject.getCharacter(defaultValue: Char?, vararg keyPath: String): Char? = - getJsonPrimitive(*keyPath).run { if ((this == null) || !isString) defaultValue else asCharacter } -fun JsonObject.getString(defaultValue: String?, vararg keyPath: String): String? = - getJsonPrimitive(*keyPath).run { if ((this == null) || !isString) defaultValue else asString } -// Other -fun JsonObject.getBoolean(defaultValue: Boolean?, vararg keyPath: String): Boolean? = - getJsonPrimitive(*keyPath).run { if ((this == null) || !isBoolean) defaultValue else asBoolean } -fun JsonObject.getNumber(defaultValue: Number?, vararg keyPath: String): Number? = - getJsonPrimitive(*keyPath).run { if ((this == null) || !isNumber) defaultValue else asNumber } \ No newline at end of file diff --git a/src/test/kotlin/Main.kt b/src/test/kotlin/Main.kt index 059b4ad..6506c61 100644 --- a/src/test/kotlin/Main.kt +++ b/src/test/kotlin/Main.kt @@ -1,11 +1,19 @@ +import city.newnan.violet.config.asConfigurationSerializable +import city.newnan.violet.config.asMap +import city.newnan.violet.config.put import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.databind.node.ObjectNode import com.fasterxml.jackson.dataformat.csv.CsvMapper import com.fasterxml.jackson.dataformat.xml.XmlMapper +import me.lucko.helper.serialize.Position +import org.bukkit.Bukkit +import org.bukkit.Material +import org.bukkit.inventory.Inventory +import org.bukkit.inventory.ItemStack fun main() { - val mapper = ObjectMapper() + val mapper = ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT) val mapper2 = CsvMapper().enable(SerializationFeature.INDENT_OUTPUT) val m = mapper.readValue("""{ |"title": "title", @@ -13,6 +21,20 @@ fun main() { |"modified": 1, |"xxx": [1,2,3,4,5] |}""".trimMargin(), ObjectNode::class.java) - val a = m["title",] - println(a) + + val x = hashMapOf( + "title" to "title", + "created" to 0, + "modified" to 1, + "xxx" to listOf(1,2,3,4,5), + "c" to hashMapOf( + "a" to 1, + "b" to 2 + ) + ) + // println(mapper.writeValueAsString(x)) + println(mapper.valueToTree(x).toPrettyString()) + + val k = m.asMap() + println(k) } \ No newline at end of file