commit 1937b0e9e1d1e4e586ed9cf79e72c76a08c9d2bd Author: CarmJos Date: Tue Jun 7 06:59:26 2022 +0800 feat: A lightweight JSON serializer diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..b5667d3 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [ CarmJos ] +custom: [ 'https://donate.carm.cc' ] diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..76e22be --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "maven" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" diff --git a/.github/gpg_public.key b/.github/gpg_public.key new file mode 100644 index 0000000..653bac3 --- /dev/null +++ b/.github/gpg_public.key @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +OK7d0W/LdJ3iFeselROADHgPQn14sg== +=rRA5 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..69fc0ec --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,108 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: "Project Deploy" + +on: + # 支持手动触发构建 + workflow_dispatch: + release: + # 创建release的时候触发 + types: [ published ] + +jobs: + packages-deploy: + name: "Publish Project (GitHub Packages)" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: "Set up JDK" + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + cache: maven + server-id: github + server-username: MAVEN_USERNAME + server-password: MAVEN_TOKEN + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import + gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase + + - name: "Packages Deploy" + run: mvn -B -Pgithub deploy --file pom.xml -DskipTests + env: + MAVEN_USERNAME: ${{ github.repository_owner }} + MAVEN_TOKEN: ${{secrets.GITHUB_TOKEN}} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + + central-deploy: + name: "Deploy Project (Central Repository)" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: "Set up JDK" + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + cache: maven + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import + gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase + + - name: "Central Deploy" + run: mvn -B -Possrh deploy --file pom.xml -DskipTests + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USER }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_PASS }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + + github-deploy: + name: "Deploy Project (GitHub Repository)" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: "Set up JDK" + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + cache: maven + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import + gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase + + - name: "Maven Deploy" + run: mvn -B -Plocal deploy --file pom.xml -DskipTests + env: + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + + - name: "Copy artifacts" + run: | + rm -rf deploy + mkdir -vp deploy + cp -vrf $HOME/local-deploy/* deploy/ + cp -vrf .documentation/REPOSITORY-README.md deploy/README.md + + - name: "Configure Git" + env: + DEPLOY_PRI: ${{secrets.DEPLOY_PRI}} + run: | + sudo timedatectl set-timezone "Asia/Shanghai" + mkdir -p ~/.ssh/ + echo "$DEPLOY_PRI" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + ssh-keyscan github.com >> ~/.ssh/known_hosts + git config --global user.name '${{ github.repository_owner }}' + git config --global user.email '${{ github.repository_owner }}@users.noreply.github.com' + + - name: "Commit&Push repository files" + run: | + cd deploy + git init + git remote add origin git@github.com:${{ github.repository_owner }}/${{ github.event.repository.name }}.git + git checkout -b repo + git add -A + git commit -m "Maven project deployment." + git push origin HEAD:repo --force \ No newline at end of file diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..bb94bbf --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,32 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Project Build & Tests + +on: + # 支持手动触发构建 + workflow_dispatch: + pull_request: + push: + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: "Set up JDK" + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + - name: "Package" + run: mvn -B package --file pom.xml -Dgpg.skip + - name: "Target Stage" + run: mkdir staging && cp target/*.jar staging + - name: "Upload artifact" + uses: actions/upload-artifact@v2 + with: + name: Artifact + path: staging diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..369777c --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/.idea/ +/target/ +**/target/ +./*.iml +*.iml +**.iml + +asset/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..153d416 --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fcb3345 --- /dev/null +++ b/README.md @@ -0,0 +1,109 @@ +# BukkitJSONSerializer + +[![version](https://img.shields.io/github/v/release/CarmJos/BukkitJSONSerializer)](https://github.com/CarmJos/BukkitJSONSerializer/releases) +[![License](https://img.shields.io/github/license/CarmJos/BukkitJSONSerializer)](https://opensource.org/licenses/MIT) +[![workflow](https://github.com/CarmJos/BukkitJSONSerializer/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/BukkitJSONSerializer/actions/workflows/maven.yml) +[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/BukkitJSONSerializer/badge)](https://www.codefactor.io/repository/github/carmjos/BukkitJSONSerializer) +![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/BukkitJSONSerializer) +![](https://visitor-badge.glitch.me/badge?page_id=BukkitJSONSerializer.readme) + +A JSON serialize/deserialize util for bukkit's ConfigurationSerialization. + +## Usage + +### Basic usage + +We cloud use `BukkitJSONSerializer#serializeToJSON(ConfigurationSerializable)` to serialize a object to JSON. + +```jave + Location location = new Location(Bukkit.getWorlds().get(0), -100.5, 100, 105.5); + String serialized = BukkitJSONSerializer.serializeToJSON(location); + // serialized -> {"world":"world","x":-100.5,"y":100,"z":105.5,"yaw":0.0,"pitch":0.0} +``` + +When we need to read the object, just use `BukkitJSONSerializer#deserializeSON(json,typeClass)` to deserialize the JSON +string. + +```java + Location deserialized=BukkitJSONSerializer.deserializeJSON(serialized,Location.class); +``` + +Or use `BukkitJSONSerializer#deserializeSON(json,typeClass,defaultValue)` if we need a default value. + +### JSONSerializable class +This project provided an interface `JSONSerializable` which provided a default method to serialize itself to JSON. + +```java +public interface JSONSerializable extends ConfigurationSerializable { + + default @NotNull String serializeToJSON() { + return BukkitJSONSerializer.serializeToJSON(this); + } + +} +``` + +## Dependency Usage + +
+Maven dependency + +```xml + + + + + + + maven + Maven Central + https://repo1.maven.org/maven2 + + + + + BukkitJSONSerializer + https://raw.githubusercontent.com/CarmJos/BukkitJSONSerializer/repo/ + + + + + + + + cc.carm.lib + bukkitjsonserializer + [LATEST RELEASE] + compile + + + + + +``` + +
+ +
+Gradle dependency + +```groovy +repositories { + + mavenCentral() // Using central repository. + + // Using github repositories. + maven { url 'https://raw.githubusercontent.com/CarmJos/BukkitJSONSerializer/repo/' } + +} + +dependencies { + api "cc.carm.lib:bukkitjsonserializer:[LATEST RELEASE]" +} +``` + +
+ +## Open Source License. + +The project using [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html) . \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2bf0796 --- /dev/null +++ b/pom.xml @@ -0,0 +1,252 @@ + + + 4.0.0 + + 8 + ${jdk.version} + ${jdk.version} + + UTF-8 + UTF-8 + + cc.carm.lib + bukkitjsonserializer + 1.0.0 + + BukkitJSONSerializer + A JSON serialize/deserialize util for bukkit's ConfigurationSerialization. + https://github.com/CarmJos/BukkitJSONSerializer + + + + CarmJos + Carm Jos + carm@carm.cc + https://www.carm.cc + Asia/Shanghai + + + + + scm:git:git@github.com:CarmJos/BukkitJSONSerializer.git + scm:git:git@github.com:CarmJos/BukkitJSONSerializer.git + https://github.com/CarmJos/BukkitJSONSerializer + HEAD + + + + + GNU LESSER GENERAL PUBLIC LICENSE + https://www.gnu.org/licenses/lgpl-3.0.html + + + + + GitHub Actions + https://github.com/CarmJos/BukkitJSONSerializer/actions/workflows/maven.yml + + + + https://github.com/CarmJos/BukkitJSONSerializer/releases + + + + + + sonatype-snapshots + Sonatype Snapshot Repository + https://s01.oss.sonatype.org/content/repositories/snapshots/ + + true + + + + + central + https://repo1.maven.org/maven2/ + + + + carm-repo + Carm's Repo + https://repo.carm.cc/repository/maven-public/ + + + + + + + + org.spigotmc + spigot + 1.8.8-R0.1-SNAPSHOT + provided + + + + org.jetbrains + annotations + 23.0.0 + provided + + + + junit + junit + 4.13.2 + test + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + false + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.4.0 + + javadoc + false + UTF-8 + UTF-8 + UTF-8 + zh_CN + + true + + cc.carm.lib:* + + + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + ${java.version} + ${java.version} + UTF-8 + -parameters + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.2 + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + package + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.0.1 + + + sign-artifacts + verify + + sign + + + + + + --pinentry-mode + loopback + + + + + org.apache.maven.plugins + maven-release-plugin + 2.5.3 + + true + false + release + deploy + + + + + + src/main/resources + true + + + + + + + + ossrh + + + ossrh + https://s01.oss.sonatype.org/content/repositories/snapshots + + + + ossrh + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + github + + + github + GitHub Packages + https://maven.pkg.github.com/CarmJos/BukkitJSONSerializer + + + + + local + + + localRepository + file:${user.home}/local-deploy/ + + + localRepository + file:${user.home}/local-deploy/ + + + + + + \ No newline at end of file diff --git a/src/main/java/cc/carm/lib/bukkit/configuration/BukkitJSONSerializer.java b/src/main/java/cc/carm/lib/bukkit/configuration/BukkitJSONSerializer.java new file mode 100644 index 0000000..72b248c --- /dev/null +++ b/src/main/java/cc/carm/lib/bukkit/configuration/BukkitJSONSerializer.java @@ -0,0 +1,162 @@ +package cc.carm.lib.bukkit.configuration; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.configuration.serialization.ConfigurationSerialization; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; + +/** + * BukkitJSONSerializer, a lightweight JSON serializer for {@link ConfigurationSerializable} objects. + *
  • serialize by {@link #serializeToJSON(ConfigurationSerializable)}
  • + *
  • deserialize by {@link #deserializeJSON(String, Class, ConfigurationSerializable)}
  • + * + * @author CarmJos + * @since 1.0.0 + */ +public class BukkitJSONSerializer { + + protected static final String TYPE_KEY = ConfigurationSerialization.SERIALIZED_TYPE_KEY; + + protected static Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + protected static JsonParser parser = new JsonParser(); + + public static void setGson(Gson gson) { + BukkitJSONSerializer.gson = gson; + } + + public static void setParser(JsonParser parser) { + BukkitJSONSerializer.parser = parser; + } + + /** + * Serializes a {@link ConfigurationSerializable} object to Map. + * + * @param value object to serialize. + * @param {@link ConfigurationSerializable} object type. + * @return Map containing serialized data + */ + public static Map serializeToMap(T value) { + Map values = new LinkedHashMap<>(); + // First, put tye type key; + values.put(TYPE_KEY, ConfigurationSerialization.getAlias(value.getClass())); + // Then, put the serialized value + value.serialize().forEach((key, sub) -> { + if (sub instanceof ConfigurationSerializable) { + values.put(key, serializeToMap((ConfigurationSerializable) sub)); + } else { + values.put(key, sub); + } + }); + return values; + } + + /** + * Serializes a {@link ConfigurationSerializable} object to JSON. + * + * @param value object to serialize. + * @param {@link ConfigurationSerializable} object type. + * @return JSON string containing serialized data. + */ + public static String serializeToJSON(T value) { + return gson.toJson(serializeToMap(value)); + } + + /** + * Deserializes a {@link ConfigurationSerializable} object from JSON. + * + * @param json JSON string to deserialize. + * @return Deserialized object. + */ + @Contract("null->null") + public static Object deserializeJSON(@Nullable String json) { + return deserializeJSON(json, (ConfigurationSerializable) null); + } + + /** + * Deserializes a {@link ConfigurationSerializable} object from JSON. + * + * @param json JSON string to deserialize. + * @param defaultValue default value to return if json is null or failed to deserialize. + * @return Deserialized object. + */ + @Contract("_,!null->!null; null,null->null") + public static ConfigurationSerializable deserializeJSON(@Nullable String json, + @Nullable ConfigurationSerializable defaultValue) { + if (json == null) return defaultValue; + Map args = jsonToMap(json); + + return Optional.ofNullable((String) args.get(TYPE_KEY)) + .map(ConfigurationSerialization::getClassByAlias) + .map(clazz -> ConfigurationSerialization.deserializeObject(args, clazz)) + .orElse(defaultValue); + } + + /** + * Deserializes a {@link ConfigurationSerializable} object from Map. + * + * @param json JSON string to deserialize. + * @param typeClazz type of object. + * @param {@link ConfigurationSerializable} object type. + * @return Deserialized object. + */ + public static @Nullable T deserializeJSON(@Nullable String json, + @NotNull Class typeClazz) { + return deserializeJSON(json, typeClazz, null); + } + + /** + * Deserializes a {@link ConfigurationSerializable} object from Map. + * + * @param json JSON string to deserialize. + * @param typeClazz type of object. + * @param defaultValue default value to return if json is null or failed to deserialize. + * @param {@link ConfigurationSerializable} object type. + * @return Deserialized object. + */ + @Contract("_,_,!null->!null; null,_,null->null") + public static T deserializeJSON(@Nullable String json, + @NotNull Class typeClazz, + @Nullable T defaultValue) { + Object value = deserializeJSON(json, defaultValue); + if (!typeClazz.isInstance(value)) return defaultValue; + + return typeClazz.cast(value); + } + + protected static Map jsonToMap(String json) { + return jsonToMap(parser.parse(json).getAsJsonObject()); + } + + protected static Map jsonToMap(JsonObject object) { + return parseMap(gson.fromJson(object, Map.class)); + } + + protected static Map parseMap(Map map) { + Map args = new LinkedHashMap<>(); + map.forEach((k, v) -> { + String key = (String) k; + if (v instanceof Map) { + Map sub = parseMap((Map) v); + if (sub.containsKey(TYPE_KEY)) { + args.put(key, ConfigurationSerialization.deserializeObject(sub)); + } else { + args.put(key, sub); + } + } else { + args.put(key, v); + } + }); + return args; + } + + +} diff --git a/src/main/java/cc/carm/lib/bukkit/configuration/JSONSerializable.java b/src/main/java/cc/carm/lib/bukkit/configuration/JSONSerializable.java new file mode 100644 index 0000000..d5bb82a --- /dev/null +++ b/src/main/java/cc/carm/lib/bukkit/configuration/JSONSerializable.java @@ -0,0 +1,17 @@ +package cc.carm.lib.bukkit.configuration; + +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.jetbrains.annotations.NotNull; + +public interface JSONSerializable extends ConfigurationSerializable { + + /** + * Serialize this object into a JSON string. + * + * @return JSON string contains serialized data. + */ + default @NotNull String serializeToJSON() { + return BukkitJSONSerializer.serializeToJSON(this); + } + +} diff --git a/src/test/java/demo.java b/src/test/java/demo.java new file mode 100644 index 0000000..ec076d6 --- /dev/null +++ b/src/test/java/demo.java @@ -0,0 +1,50 @@ +import cc.carm.lib.bukkit.configuration.BukkitJSONSerializer; +import cc.carm.lib.bukkit.configuration.JSONSerializable; +import org.bukkit.Bukkit; +import org.bukkit.Location; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; + +public class demo { + + public static void demoUsage() { + + Location location = new Location(Bukkit.getWorlds().get(0), -100.5, 100, 105.5); + + String serialized = BukkitJSONSerializer.serializeToJSON(location); + // serialized -> {"world":"world","x":-100.5,"y":100,"z":105.5,"yaw":0.0,"pitch":0.0} + + Location deserialized = BukkitJSONSerializer.deserializeJSON(serialized, Location.class); + + } + + public static final class SomeValue implements JSONSerializable { + + long time; + UUID uuid; + + public SomeValue(long time, UUID uuid) { + this.time = time; + this.uuid = uuid; + } + + @Override + public Map serialize() { + Map map = new LinkedHashMap<>(); + map.put("time", time); + map.put("uuid", uuid.toString()); + return map; + } + + public static SomeValue deserialize(Map map) { + return new SomeValue( + (long) map.get("time"), + UUID.fromString((String) map.get("uuid")) + ); + } + + } + +} \ No newline at end of file