From 3ce75bf7a80fa18ac67b690059748a75f4656d4b Mon Sep 17 00:00:00 2001 From: zml Date: Sat, 21 Dec 2024 19:40:16 -0800 Subject: [PATCH] fix(text-serializer-gson): correctly handle removed data components Fixes GH-1131 --- .../serializer/gson/ShowItemSerializer.java | 26 ++++++++++++++--- .../json/ShowItemSerializerTest.java | 28 +++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowItemSerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowItemSerializer.java index b46bbdc3f..3de4ee2b1 100644 --- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowItemSerializer.java +++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowItemSerializer.java @@ -25,6 +25,7 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; +import com.google.gson.JsonNull; import com.google.gson.JsonParseException; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; @@ -49,6 +50,7 @@ final class ShowItemSerializer extends TypeAdapter { @SuppressWarnings("deprecation") private static final String LEGACY_SHOW_ITEM_TAG = net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ITEM_TAG; + private static final String DATA_COMPONENT_REMOVAL_PREFIX = "!"; private final Gson gson; private final boolean emitDefaultQuantity; @@ -94,12 +96,22 @@ public HoverEvent.ShowItem read(final JsonReader in) throws IOException { } else if (fieldName.equals(SHOW_ITEM_COMPONENTS)) { in.beginObject(); while (in.peek() != JsonToken.END_OBJECT) { - final Key id = Key.key(in.nextName()); + final String name = in.nextName(); + final Key id; + final boolean removed; + if (name.startsWith(DATA_COMPONENT_REMOVAL_PREFIX)) { + id = Key.key(name.substring(1)); + removed = true; + } else { + id = Key.key(name); + removed = false; + } + final JsonElement tree = this.gson.fromJson(in, JsonElement.class); if (dataComponents == null) { dataComponents = new HashMap<>(); } - dataComponents.put(id, GsonDataComponentValue.gsonDataComponentValue(tree)); + dataComponents.put(id, removed ? DataComponentValue.removed() : GsonDataComponentValue.gsonDataComponentValue(tree)); } in.endObject(); } else { @@ -137,8 +149,14 @@ public void write(final JsonWriter out, final HoverEvent.ShowItem value) throws out.name(SHOW_ITEM_COMPONENTS); out.beginObject(); for (final Map.Entry entry : value.dataComponentsAs(GsonDataComponentValue.class).entrySet()) { - out.name(entry.getKey().asString()); - this.gson.toJson(entry.getValue().element(), out); + final JsonElement el = entry.getValue().element();; + if (el instanceof JsonNull) { // removed + out.name(DATA_COMPONENT_REMOVAL_PREFIX + entry.getKey().asString()); + out.beginObject().endObject(); + } else { + out.name(entry.getKey().asString()); + this.gson.toJson(el, out); + } } out.endObject(); } else if (this.itemDataMode != JSONOptions.ShowItemHoverDataMode.EMIT_DATA_COMPONENTS) { diff --git a/text-serializer-json/src/testFixtures/java/net/kyori/adventure/text/serializer/json/ShowItemSerializerTest.java b/text-serializer-json/src/testFixtures/java/net/kyori/adventure/text/serializer/json/ShowItemSerializerTest.java index 2a1286655..2c8729058 100644 --- a/text-serializer-json/src/testFixtures/java/net/kyori/adventure/text/serializer/json/ShowItemSerializerTest.java +++ b/text-serializer-json/src/testFixtures/java/net/kyori/adventure/text/serializer/json/ShowItemSerializerTest.java @@ -23,6 +23,7 @@ */ package net.kyori.adventure.text.serializer.json; +import com.google.gson.JsonObject; import java.io.IOException; import java.util.Collections; import net.kyori.adventure.key.Key; @@ -31,6 +32,7 @@ import net.kyori.adventure.nbt.TagStringIO; import net.kyori.adventure.nbt.api.BinaryTagHolder; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.DataComponentValue; import net.kyori.adventure.text.event.HoverEvent; import org.junit.jupiter.api.Test; @@ -124,4 +126,30 @@ void testDeserializeWithCountOfOne() throws IOException { } ); } + + @Test + void testDeserializeWithRemovedComponent() { + this.testObject( + Component.text().hoverEvent( + HoverEvent.showItem( + Key.key("minecraft", "diamond"), + 2, + Collections.singletonMap(Key.key("minecraft", "damage"), DataComponentValue.removed()) + ) + ).build(), + json -> { + json.addProperty(JSONComponentConstants.TEXT, ""); + json.add(JSONComponentConstants.HOVER_EVENT, object(hover -> { + hover.addProperty(JSONComponentConstants.HOVER_EVENT_ACTION, name(HoverEvent.Action.SHOW_ITEM)); + hover.add(JSONComponentConstants.HOVER_EVENT_CONTENTS, object(contents -> { + contents.addProperty(JSONComponentConstants.SHOW_ITEM_ID, "minecraft:diamond"); + contents.addProperty(JSONComponentConstants.SHOW_ITEM_COUNT, 2); + contents.add(JSONComponentConstants.SHOW_ITEM_COMPONENTS, object(comps -> { + comps.add("!minecraft:damage", new JsonObject()); + })); + })); + })); + } + ); + } }