Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added GSON serialization for Tags #2614

Merged
merged 1 commit into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions src/main/java/world/bentobox/bentobox/api/user/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -37,6 +38,7 @@ protected AbstractJSONDatabaseHandler(BentoBox plugin, Class<T> 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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -62,6 +65,7 @@ public BentoboxTypeAdapterFactory(BentoBox plugin) {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Class<?> rawType = type.getRawType();

if (Location.class.isAssignableFrom(rawType)) {
// Use our current location adapter for backward compatibility
return (TypeAdapter<T>) new LocationTypeAdapter();
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <T> Tag class to be serialized
*/
public final class TagTypeAdapter<E extends Keyed> extends TypeAdapter<Tag<E>> {
private final TypeAdapter<String> stringAdapter;
private final String registry;
private final Class<E> elementType;

public TagTypeAdapter(Gson gson, String registry, Class<E> elementType) {
this.stringAdapter = gson.getAdapter(String.class);
this.registry = registry;
this.elementType = elementType;
}

@Override
public void write(JsonWriter out, Tag<E> value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
stringAdapter.write(out, value.getKey().toString());
}

@Override
public Tag<E> 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<E> tag = Bukkit.getTag(registry, namespacedKey, elementType);
if (tag == null) {
throw new JsonParseException("Unknown tag: " + key);
}

return tag;
}
}
Original file line number Diff line number Diff line change
@@ -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 <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Class<?> rawType = type.getRawType();
if (Tag.class.isAssignableFrom(rawType)) {
// Get the generic type parameter of Tag<T>
Type[] typeArguments = ((ParameterizedType) type.getType()).getActualTypeArguments();
if (typeArguments.length > 0) {
Class<? extends Keyed> tagType = (Class<? extends Keyed>) 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<T>) new TagTypeAdapter(gson, registry, tagType);
}
}
return null;
}
}