From 2a57f723cc14c0731bb1eaebc2a58014c70aab85 Mon Sep 17 00:00:00 2001 From: Gk0Wk Date: Sat, 5 Aug 2023 13:52:17 +0800 Subject: [PATCH] update COnfigManager2 --- docs/config.md | 14 +++ .../newnan/violet/config/ConfigManager2.kt | 113 +++++++++++++++--- .../violet/config/JsonObjectExtension.kt | 8 +- src/test/kotlin/Main.kt | 66 +++++----- 4 files changed, 146 insertions(+), 55 deletions(-) diff --git a/docs/config.md b/docs/config.md index 8490f24..58f2359 100644 --- a/docs/config.md +++ b/docs/config.md @@ -30,6 +30,15 @@ config.root { val inventory = it["inventory"].asBase64Inventory() val location = it["location"].asConfigurationSerializable() } + +// Class mapping mode +data class Config( + val a: Int, + val b: String, +) +val c1 = ConfigManager2.parse("""{"a":1,"b":"a"}""", ConfigManager2.ConfigFileType.Json) // to object +val c2 = ConfigManager2.parse(File("/root/example/config.yml")) // parse object from file +val c3 = configManager.parse("config.yml") // parse object from config ``` Write: @@ -43,6 +52,11 @@ configManager["store.json"].save { it.setBase64("example-inventory", Bukkit.getOfflinePlayers()[0].player!!.inventory) it.remove("foo") } + +// Class mapping mode +ConfigManager2.stringify(Config(1, "a"), ConfigManager2.ConfigFileType.Json) // to string: {"a":1,"b":"a"} +ConfigManager2.save(Config(1, "a"), File("/root/example/config.yml")) // save object to file +configManager.save(Config(1, "a"), "config.yml") // save object to config ``` Multi-type support: diff --git a/src/main/kotlin/city/newnan/violet/config/ConfigManager2.kt b/src/main/kotlin/city/newnan/violet/config/ConfigManager2.kt index 8ab74fa..f596225 100644 --- a/src/main/kotlin/city/newnan/violet/config/ConfigManager2.kt +++ b/src/main/kotlin/city/newnan/violet/config/ConfigManager2.kt @@ -2,6 +2,7 @@ package city.newnan.violet.config +import com.fasterxml.jackson.core.JsonProcessingException import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature @@ -49,9 +50,9 @@ class Configure2( /** * 配置文件启用或关闭持久化保存,即不会因为长久未访问就从内存中卸载,适合经常访问的配置文件。 */ - fun setCache(enable: Boolean) { - if (path == null) return - if (enable == _enableCache) return + fun setCache(enable: Boolean): Configure2 { + if (path == null) return this + if (enable == _enableCache) return this _enableCache = enable val p = path!!.canonicalPath if (enable) { @@ -64,6 +65,7 @@ class Configure2( manager.persistentConfigSet.remove(p) save() } + return this } /** * 配置文件启用或关闭持久化保存,即不会因为长久未访问就从内存中卸载,适合经常访问的配置文件。 @@ -83,11 +85,12 @@ class Configure2( * * @param enable 是否启动持久化 */ - fun setPersistence(enable: Boolean) { - if (path == null) return - if (enable == _enablePersistence) return + fun setPersistence(enable: Boolean): Configure2 { + if (path == null) return this + if (enable == _enablePersistence) return this _enablePersistence = enable if (enable) manager.persistentConfigSet.add(path!!.canonicalPath) + return this } /** * 将某个文件设置为持久化保存的,即不会因为长久未访问就从内存中卸载;或者取消。以缓存为前提。 @@ -95,6 +98,7 @@ class Configure2( * @param enable 是否启动持久化 */ infix fun persistence(enable: Boolean) = setPersistence(enable) + fun persistence() = persistence(true) /** * 配置文件路径 @@ -284,16 +288,15 @@ class ConfigManager2 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 - } + private fun decorateMapper(mapper: ObjectMapper): ObjectMapper = mapper + // 序列化时使用缩进 + .enable(SerializationFeature.INDENT_OUTPUT) + // 解析时忽略未知的属性 + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + // 支持 Kotlin 类 + // https://github.com/FasterXML/jackson-module-kotlin + .registerKotlinModule() + /** * 获取一个 mapper @@ -322,6 +325,52 @@ class ConfigManager2 "conf", "hocon" -> ConfigFileType.Hocon else -> throw UnknownConfigFileFormatException(path.path) } + + /** + * 使用指定类型解析配置文件 + * + * @param T 指定类型 + * @param path 配置文件路径 + * @param type 配置文件类型,如果为null则自动检测 + * @return [T] 实例 + */ + @Throws(IOException::class, UnknownConfigFileFormatException::class) + inline fun parse(path: File, type: ConfigFileType? = null): T { + // 读取配置文件 + val typeReal = type ?: guessConfigType(path) + return mapper[typeReal].readValue(path, T::class.java) + } + + /** + * 使用指定类型解析文本 + * + * @param T 指定类型 + * @param config 配置文本 + * @param type 配置文件类型 + * @return [T] 实例 + */ + @Throws(JsonProcessingException::class, UnknownConfigFileFormatException::class) + inline fun parse(config: String, type: ConfigFileType): T { + return mapper[type].readValue(config, T::class.java) + } + + /** + * 序列化为文本 + * + * @param T 指定类型 + * @param type 配置文件类型 + * @return [String] 文本 + */ + @Throws(JsonProcessingException::class, UnknownConfigFileFormatException::class) + inline fun stringify(obj: T, type: ConfigFileType): String { + return mapper[type].writeValueAsString(obj) + } + + @Throws(IOException::class, UnknownConfigFileFormatException::class) + inline fun save(obj: T, path: File, type: ConfigFileType? = null) { + val typeReal = type ?: guessConfigType(path) + mapper[typeReal].writeValue(path, obj) + } } /** @@ -483,6 +532,7 @@ class ConfigManager2 /** * 直接从文件获取某个配置文件(支持YAML,JSON,TOML,HOCON,XML,Properties和CSV),不使用缓存机制 * @param configFile 配置文件路径 + * @param type 配置文件类型,如果为null则自动检测 * @return 配置实例 * @throws IOException 文件读写出错 * @throws UnknownConfigFileFormatException 未知的配置文件格式 @@ -497,6 +547,37 @@ class ConfigManager2 return Configure2(path, typeReal, mapper[typeReal].readTree(path) as ObjectNode, this) } + /** + * 使用指定类型解析配置文件 + * + * @param T 指定类型 + * @param configFile 配置文件路径 + * @param type 配置文件类型,如果为null则自动检测 + * @return [T] 实例 + */ + @Throws(IOException::class, UnknownConfigFileFormatException::class) + inline fun parse(configFile: String, type: ConfigFileType? = null): T { + // 未缓存则加载 + touch(configFile) + // 读取配置文件 + return parse(File(plugin.dataFolder, configFile), type) + } + + /** + * 序列化对象到指定的配置文件 + * + * @param T 指定类型 + * @param obj 对象实例 + * @param configFile 配置文件路径 + * @param type 配置文件类型,如果为null则自动检测 + * @return [T] 实例 + */ + @Throws(IOException::class, UnknownConfigFileFormatException::class) + inline fun save(obj: T, configFile: String, type: ConfigFileType? = null) { + // 读取配置文件 + save(obj, File(plugin.dataFolder, configFile), type) + } + /** * 获取某个配置文件(支持YAML,JSON和HOCON),如果不存在就从指定的模板复制一份 * @param targetFile 要获取的配置文件路径 diff --git a/src/main/kotlin/city/newnan/violet/config/JsonObjectExtension.kt b/src/main/kotlin/city/newnan/violet/config/JsonObjectExtension.kt index 8c50854..ae8cf6f 100644 --- a/src/main/kotlin/city/newnan/violet/config/JsonObjectExtension.kt +++ b/src/main/kotlin/city/newnan/violet/config/JsonObjectExtension.kt @@ -41,13 +41,13 @@ 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 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 JsonNode.asList() = asType>() fun List<*>.toObjectNode(): ObjectNode = ConfigManager2.mapper[ConfigManager2.ConfigFileType.Json] .valueToTree(this) fun ObjectNode.put(key: String, value: List<*>) { @@ -66,9 +66,9 @@ 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? + = ConfigurationSerialization.deserializeObject(asMap()) as T? fun JsonNode.asBase64Inventory(): Inventory { - val map = asMap() + val map = asMap() return InventorySerialization.decodeInventory(map["data"] as String, map["title"] as String) } fun JsonNode.asBase64ItemStacks(): Array diff --git a/src/test/kotlin/Main.kt b/src/test/kotlin/Main.kt index 6506c61..74213a9 100644 --- a/src/test/kotlin/Main.kt +++ b/src/test/kotlin/Main.kt @@ -1,40 +1,36 @@ -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 +import city.newnan.violet.config.ConfigManager2 + +data class Area(val a: String, val b: Int) fun main() { - val mapper = ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT) - val mapper2 = CsvMapper().enable(SerializationFeature.INDENT_OUTPUT) - val m = mapper.readValue("""{ - |"title": "title", - |"created": 0, - |"modified": 1, - |"xxx": [1,2,3,4,5] - |}""".trimMargin(), ObjectNode::class.java) +// val mapper2 = CsvMapper().enable(SerializationFeature.INDENT_OUTPUT) +// val m = mapper.readValue("""{ +// |"title": "title", +// |"created": 0, +// |"modified": 1, +// |"xxx": [1,2,3,4,5] +// |}""".trimMargin(), ObjectNode::class.java) +// +// 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) - 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 - ) + val a = hashMapOf( + "a" to Area("a", 1), + "b" to Area("b", 2) ) - // println(mapper.writeValueAsString(x)) - println(mapper.valueToTree(x).toPrettyString()) - - val k = m.asMap() - println(k) + ConfigManager2.stringify(a, ConfigManager2.ConfigFileType.Json).also(::println) + ConfigManager2.parse>(ConfigManager2.stringify(a, ConfigManager2.ConfigFileType.Json), ConfigManager2.ConfigFileType.Json).also(::println) } \ No newline at end of file