From 1d76fe756409857d8c1a14251739a47182476ed5 Mon Sep 17 00:00:00 2001 From: tastybento Date: Mon, 3 Feb 2025 16:31:27 -0800 Subject: [PATCH] Added GSON serialization for Tags --- .../bentobox/bentobox/api/user/User.java | 32 +++++----- .../json/AbstractJSONDatabaseHandler.java | 2 + .../json/BentoboxTypeAdapterFactory.java | 4 ++ .../json/adapters/TagTypeAdapter.java | 63 +++++++++++++++++++ .../json/adapters/TagTypeAdapterFactory.java | 45 +++++++++++++ 5 files changed, 130 insertions(+), 16 deletions(-) create mode 100644 src/main/java/world/bentobox/bentobox/database/json/adapters/TagTypeAdapter.java create mode 100644 src/main/java/world/bentobox/bentobox/database/json/adapters/TagTypeAdapterFactory.java diff --git a/src/main/java/world/bentobox/bentobox/api/user/User.java b/src/main/java/world/bentobox/bentobox/api/user/User.java index 0951ae4b5..a7bb92df0 100644 --- a/src/main/java/world/bentobox/bentobox/api/user/User.java +++ b/src/main/java/world/bentobox/bentobox/api/user/User.java @@ -643,22 +643,22 @@ public void sendRawMessage(String message) { // Apply the first valid click event or hover event encountered switch (actionType) { - case "RUN_COMMAND": - case "SUGGEST_COMMAND": - case "COPY_TO_CLIPBOARD": - case "OPEN_URL": - if (clickEvent == null) { - clickEvent = new ClickEvent(ClickEvent.Action.valueOf(actionType), actionValue); - } - break; - case "HOVER": - if (hoverEvent == null) { - hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(actionValue)); - } - break; - default: - // Unrecognized command; preserve it in the output text - baseComponent.addExtra(TextComponent.fromLegacy(matcher.group(0))); + case "RUN_COMMAND": + case "SUGGEST_COMMAND": + case "COPY_TO_CLIPBOARD": + case "OPEN_URL": + if (clickEvent == null) { + clickEvent = new ClickEvent(ClickEvent.Action.valueOf(actionType), actionValue); + } + break; + case "HOVER": + if (hoverEvent == null) { + hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(actionValue)); + } + break; + default: + // Unrecognized command; preserve it in the output text + baseComponent.addExtra(TextComponent.fromLegacy(matcher.group(0))); } } else if (matcher.group(3) != null) { diff --git a/src/main/java/world/bentobox/bentobox/database/json/AbstractJSONDatabaseHandler.java b/src/main/java/world/bentobox/bentobox/database/json/AbstractJSONDatabaseHandler.java index 8f4e7e105..8cb0793bc 100644 --- a/src/main/java/world/bentobox/bentobox/database/json/AbstractJSONDatabaseHandler.java +++ b/src/main/java/world/bentobox/bentobox/database/json/AbstractJSONDatabaseHandler.java @@ -6,6 +6,7 @@ import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.database.AbstractDatabaseHandler; import world.bentobox.bentobox.database.DatabaseConnector; +import world.bentobox.bentobox.database.json.adapters.TagTypeAdapterFactory; /** * Abstract class that handles insert/select-operations into/from a database. @@ -37,6 +38,7 @@ protected AbstractJSONDatabaseHandler(BentoBox plugin, Class type, DatabaseCo GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization().setPrettyPrinting(); // Register adapter factory builder.registerTypeAdapterFactory(new BentoboxTypeAdapterFactory(plugin)); + builder.registerTypeAdapterFactory(new TagTypeAdapterFactory()); // Allow characters like < or > without escaping them builder.disableHtmlEscaping(); diff --git a/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java b/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java index 6615ced50..94a6ef560 100644 --- a/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java +++ b/src/main/java/world/bentobox/bentobox/database/json/BentoboxTypeAdapterFactory.java @@ -6,6 +6,8 @@ import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Registry; +import org.bukkit.Tag; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.configuration.serialization.ConfigurationSerializable; @@ -32,6 +34,7 @@ import world.bentobox.bentobox.database.json.adapters.PairTypeAdapter; import world.bentobox.bentobox.database.json.adapters.PotionEffectTypeAdapter; import world.bentobox.bentobox.database.json.adapters.ProfessionTypeAdapter; +import world.bentobox.bentobox.database.json.adapters.TagTypeAdapter; import world.bentobox.bentobox.database.json.adapters.VectorTypeAdapter; import world.bentobox.bentobox.database.json.adapters.VillagerTypeAdapter; import world.bentobox.bentobox.database.json.adapters.WorldTypeAdapter; @@ -62,6 +65,7 @@ public BentoboxTypeAdapterFactory(BentoBox plugin) { @Override public TypeAdapter create(Gson gson, TypeToken type) { Class rawType = type.getRawType(); + if (Location.class.isAssignableFrom(rawType)) { // Use our current location adapter for backward compatibility return (TypeAdapter) new LocationTypeAdapter(); diff --git a/src/main/java/world/bentobox/bentobox/database/json/adapters/TagTypeAdapter.java b/src/main/java/world/bentobox/bentobox/database/json/adapters/TagTypeAdapter.java new file mode 100644 index 000000000..3dc72addc --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/database/json/adapters/TagTypeAdapter.java @@ -0,0 +1,63 @@ +package world.bentobox.bentobox.database.json.adapters; + +import java.io.IOException; + +import org.bukkit.Bukkit; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; + +import com.google.gson.Gson; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + + +/** + * @author tastybento + * + * @param Tag class to be serialized + */ +public final class TagTypeAdapter extends TypeAdapter> { + private final TypeAdapter stringAdapter; + private final String registry; + private final Class elementType; + + public TagTypeAdapter(Gson gson, String registry, Class elementType) { + this.stringAdapter = gson.getAdapter(String.class); + this.registry = registry; + this.elementType = elementType; + } + + @Override + public void write(JsonWriter out, Tag value) throws IOException { + if (value == null) { + out.nullValue(); + return; + } + stringAdapter.write(out, value.getKey().toString()); + } + + @Override + public Tag read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + String key = stringAdapter.read(in); + NamespacedKey namespacedKey = NamespacedKey.fromString(key); + if (namespacedKey == null) { + throw new JsonParseException("Invalid tag key format: " + key); + } + + Tag tag = Bukkit.getTag(registry, namespacedKey, elementType); + if (tag == null) { + throw new JsonParseException("Unknown tag: " + key); + } + + return tag; + } +} \ No newline at end of file diff --git a/src/main/java/world/bentobox/bentobox/database/json/adapters/TagTypeAdapterFactory.java b/src/main/java/world/bentobox/bentobox/database/json/adapters/TagTypeAdapterFactory.java new file mode 100644 index 000000000..8097c4c07 --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/database/json/adapters/TagTypeAdapterFactory.java @@ -0,0 +1,45 @@ +package world.bentobox.bentobox.database.json.adapters; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import org.bukkit.Fluid; +import org.bukkit.Keyed; +import org.bukkit.Material; +import org.bukkit.Tag; +import org.bukkit.entity.EntityType; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; + +public class TagTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + Class rawType = type.getRawType(); + if (Tag.class.isAssignableFrom(rawType)) { + // Get the generic type parameter of Tag + Type[] typeArguments = ((ParameterizedType) type.getType()).getActualTypeArguments(); + if (typeArguments.length > 0) { + Class tagType = (Class) typeArguments[0]; + + // Determine the correct registry based on the tag type + String registry; + if (Material.class.equals(tagType)) { + registry = Tag.REGISTRY_BLOCKS; + } else if (EntityType.class.equals(tagType)) { + registry = Tag.REGISTRY_ENTITY_TYPES; + } else if (Fluid.class.equals(tagType)) { + registry = Tag.REGISTRY_FLUIDS; + } else { + throw new IllegalArgumentException("Unsupported Tag type: " + tagType); + } + + return (TypeAdapter) new TagTypeAdapter(gson, registry, tagType); + } + } + return null; + } +} \ No newline at end of file