1
mirror of https://github.com/CarmJos/BukkitJSONSerializer.git synced 2026-06-04 16:48:18 +08:00

feat: A lightweight JSON serializer

This commit is contained in:
2022-06-07 06:59:26 +08:00
commit 1937b0e9e1
12 changed files with 957 additions and 0 deletions
@@ -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.
* <li>serialize by {@link #serializeToJSON(ConfigurationSerializable)}</li>
* <li>deserialize by {@link #deserializeJSON(String, Class, ConfigurationSerializable)}</li>
*
* @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 <T> {@link ConfigurationSerializable} object type.
* @return Map containing serialized data
*/
public static <T extends ConfigurationSerializable> Map<String, Object> serializeToMap(T value) {
Map<String, Object> 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 <T> {@link ConfigurationSerializable} object type.
* @return JSON string containing serialized data.
*/
public static <T extends ConfigurationSerializable> 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<String, Object> 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 <T> {@link ConfigurationSerializable} object type.
* @return Deserialized object.
*/
public static <T extends ConfigurationSerializable> @Nullable T deserializeJSON(@Nullable String json,
@NotNull Class<T> 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 <T> {@link ConfigurationSerializable} object type.
* @return Deserialized object.
*/
@Contract("_,_,!null->!null; null,_,null->null")
public static <T extends ConfigurationSerializable> T deserializeJSON(@Nullable String json,
@NotNull Class<T> typeClazz,
@Nullable T defaultValue) {
Object value = deserializeJSON(json, defaultValue);
if (!typeClazz.isInstance(value)) return defaultValue;
return typeClazz.cast(value);
}
protected static Map<String, Object> jsonToMap(String json) {
return jsonToMap(parser.parse(json).getAsJsonObject());
}
protected static Map<String, Object> jsonToMap(JsonObject object) {
return parseMap(gson.fromJson(object, Map.class));
}
protected static Map<String, Object> parseMap(Map<?, ?> map) {
Map<String, Object> args = new LinkedHashMap<>();
map.forEach((k, v) -> {
String key = (String) k;
if (v instanceof Map<?, ?>) {
Map<String, Object> 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;
}
}
@@ -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);
}
}
+50
View File
@@ -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<String, Object> serialize() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("time", time);
map.put("uuid", uuid.toString());
return map;
}
public static SomeValue deserialize(Map<String, Object> map) {
return new SomeValue(
(long) map.get("time"),
UUID.fromString((String) map.get("uuid"))
);
}
}
}