package cc.maxmc.servux.util import com.google.gson.* import org.bukkit.util.Vector import taboolib.common.platform.function.info import taboolib.common.platform.function.warning import taboolib.platform.BukkitPlugin import java.io.File import java.io.FileReader import java.io.FileWriter import java.io.IOException object JsonUtils { val GSON = GsonBuilder().setPrettyPrinting().create() fun getNestedObject(parent: JsonObject, key: String?, create: Boolean): JsonObject? { return if (!parent.has(key) || !parent[key].isJsonObject) { if (!create) { return null } val obj = JsonObject() parent.add(key, obj) obj } else { parent[key].asJsonObject } } fun hasBoolean(obj: JsonObject, name: String?): Boolean { val el = obj[name] if (el != null && el.isJsonPrimitive) { try { el.asBoolean return true } catch (_: Exception) { } } return false } fun hasInteger(obj: JsonObject, name: String?): Boolean { val el = obj[name] if (el != null && el.isJsonPrimitive) { try { el.asInt return true } catch (e: Exception) { } } return false } fun hasLong(obj: JsonObject, name: String?): Boolean { val el = obj[name] if (el != null && el.isJsonPrimitive) { try { el.asLong return true } catch (_: Exception) { } } return false } fun hasFloat(obj: JsonObject, name: String?): Boolean { val el = obj[name] if (el != null && el.isJsonPrimitive) { try { el.asFloat return true } catch (_: Exception) { } } return false } fun hasDouble(obj: JsonObject, name: String?): Boolean { val el = obj[name] if (el != null && el.isJsonPrimitive) { try { el.asDouble return true } catch (_: Exception) { } } return false } fun hasString(obj: JsonObject, name: String?): Boolean { val el = obj[name] if (el != null && el.isJsonPrimitive) { try { el.asString return true } catch (_: Exception) { } } return false } fun hasObject(obj: JsonObject, name: String?): Boolean { val el = obj[name] return el != null && el.isJsonObject } fun hasArray(obj: JsonObject, name: String?): Boolean { val el = obj[name] return el != null && el.isJsonArray } fun getBooleanOrDefault(obj: JsonObject, name: String?, defaultValue: Boolean): Boolean { if (obj.has(name) && obj[name].isJsonPrimitive) { try { return obj[name].asBoolean } catch (e: Exception) { } } return defaultValue } fun getIntegerOrDefault(obj: JsonObject, name: String?, defaultValue: Int): Int { if (obj.has(name) && obj[name].isJsonPrimitive) { try { return obj[name].asInt } catch (e: Exception) { } } return defaultValue } fun getLongOrDefault(obj: JsonObject, name: String?, defaultValue: Long): Long { if (obj.has(name) && obj[name].isJsonPrimitive) { try { return obj[name].asLong } catch (e: Exception) { } } return defaultValue } fun getFloatOrDefault(obj: JsonObject, name: String?, defaultValue: Float): Float { if (obj.has(name) && obj[name].isJsonPrimitive) { try { return obj[name].asFloat } catch (e: Exception) { } } return defaultValue } fun getDoubleOrDefault(obj: JsonObject, name: String?, defaultValue: Double): Double { if (obj.has(name) && obj[name].isJsonPrimitive) { try { return obj[name].asDouble } catch (e: Exception) { } } return defaultValue } fun getStringOrDefault(obj: JsonObject, name: String?, defaultValue: String?): String? { if (obj.has(name) && obj[name].isJsonPrimitive) { try { return obj[name].asString } catch (e: Exception) { } } return defaultValue } fun getBoolean(obj: JsonObject, name: String?): Boolean { return getBooleanOrDefault(obj, name, false) } fun getInteger(obj: JsonObject, name: String?): Int { return getIntegerOrDefault(obj, name, 0) } fun getLong(obj: JsonObject, name: String?): Long { return getLongOrDefault(obj, name, 0) } fun getFloat(obj: JsonObject, name: String?): Float { return getFloatOrDefault(obj, name, 0f) } fun getDouble(obj: JsonObject, name: String?): Double { return getDoubleOrDefault(obj, name, 0.0) } fun getString(obj: JsonObject, name: String?): String? { return getStringOrDefault(obj, name, null) } fun hasBlockPos(obj: JsonObject, name: String?): Boolean { return blockPosFromJson(obj, name) != null } fun blockPosToJson(pos: Vector): JsonArray { val arr = JsonArray() arr.add(pos.x) arr.add(pos.y) arr.add(pos.z) return arr } fun blockPosFromJson(obj: JsonObject, name: String?): Vector? { if (hasArray(obj, name)) { val arr = obj.getAsJsonArray(name) if (arr.size() == 3) { try { return Vector(arr[0].asInt, arr[1].asInt, arr[2].asInt) } catch (ignored: Exception) { } } } return null } fun hasVec3d(obj: JsonObject, name: String?): Boolean { return vec3dFromJson(obj, name) != null } fun vec3dToJson(vec: Vector): JsonArray { val arr = JsonArray() arr.add(vec.x) arr.add(vec.y) arr.add(vec.z) return arr } fun vec3dFromJson(obj: JsonObject, name: String?): Vector? { if (hasArray(obj, name)) { val arr = obj.getAsJsonArray(name) if (arr.size() == 3) { try { return Vector(arr[0].asDouble, arr[1].asDouble, arr[2].asDouble) } catch (e: Exception) { } } } return null } // https://stackoverflow.com/questions/29786197/gson-jsonobject-copy-value-affected-others-jsonobject-instance fun deepCopy(jsonObject: JsonObject): JsonObject { val result = JsonObject() for ((key, value) in jsonObject.entrySet()) { result.add(key, deepCopy(value)) } return result } fun deepCopy(jsonArray: JsonArray): JsonArray { val result = JsonArray() for (e in jsonArray) { result.add(deepCopy(e)) } return result } fun deepCopy(jsonElement: JsonElement): JsonElement { return if (jsonElement.isJsonPrimitive || jsonElement.isJsonNull) { jsonElement // these are immutable anyway } else if (jsonElement.isJsonObject) { deepCopy(jsonElement.asJsonObject) } else if (jsonElement.isJsonArray) { deepCopy(jsonElement.asJsonArray) } else { throw UnsupportedOperationException("Unsupported element: $jsonElement") } } fun parseJsonFromString(str: String?): JsonElement? { try { val parser = JsonParser() return parser.parse(str) } catch (e: Exception) { } return null } fun parseJsonFile(file: File?): JsonElement? { if (file != null && file.exists() && file.isFile && file.canRead()) { val fileName = file.absolutePath try { val parser = JsonParser() val reader = FileReader(file) val element = parser.parse(reader) reader.close() return element } catch (e: Exception) { warning("Failed to parse the JSON file '" + fileName + "'" + e.message) } } return null } /** * Converts the given JsonElement tree into its string representation. * If **compact** is true, then it's written in one line without spaces or line breaks. * * @param element * @param compact * @return */ fun jsonToString(element: JsonElement?, compact: Boolean): String { val gson = if (compact) Gson() else GSON return gson.toJson(element) } fun writeJsonToFile(root: JsonElement?, file: File): Boolean { return writeJsonToFile(GSON, root, file) } fun writeJsonToFile(gson: Gson, root: JsonElement?, file: File): Boolean { var writer: FileWriter? = null try { writer = FileWriter(file) writer.write(gson.toJson(root)) writer.close() return true } catch (e: IOException) { warning("Failed to write JSON data to file '" + file.absolutePath + "'" + e.message) } finally { try { writer?.close() } catch (e: Exception) { warning("Failed to close JSON file" + e.message) } } return false } }