Repository: kyoripowered/adventure
Issue: Unable to handle Empty Hover Event Value/Contents Array

Weirdly enough, vanilla Minecraft actually accepts a json string like this as a valid chat component.
```json
{"text": "hello", "hoverEvent":{"action":"show_text","value":[]}}
```
AND
```json
{"text": "hello", "hoverEvent":{"action":"show_text","contents":[]}}
```
Which in game, the whole hoverEvent would just be ignored.
But with Adventure, it'll not know what to do/throw an error.
```
[02:25:32 INFO]: com.google.gson.JsonParseException: Don't know how to turn [] into a Component
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.ComponentSerializerImpl.notSureHowToDeserialize(ComponentSerializerImpl.java:262) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.ComponentSerializerImpl.deserialize0(ComponentSerializerImpl.java:92) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.ComponentSerializerImpl.deserialize(ComponentSerializerImpl.java:75) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.ComponentSerializerImpl.deserialize(ComponentSerializerImpl.java:55) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.Gson.fromJson(Gson.java:887) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.Gson.fromJson(Gson.java:952) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.deserialize(TreeTypeAdapter.java:162) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.StyleSerializer.deserialize(StyleSerializer.java:155) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.StyleSerializer.deserialize(StyleSerializer.java:98) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.StyleSerializer.deserialize(StyleSerializer.java:53) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.Gson.fromJson(Gson.java:887) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.Gson.fromJson(Gson.java:952) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.deserialize(TreeTypeAdapter.java:162) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.ComponentSerializerImpl.deserialize0(ComponentSerializerImpl.java:161) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.ComponentSerializerImpl.deserialize(ComponentSerializerImpl.java:75) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.ComponentSerializerImpl.deserialize(ComponentSerializerImpl.java:55) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.Gson.fromJson(Gson.java:887) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.Gson.fromJson(Gson.java:852) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.Gson.fromJson(Gson.java:801) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at com.google.gson.Gson.fromJson(Gson.java:773) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.GsonComponentSerializerImpl.deserialize(GsonComponentSerializerImpl.java:101) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
[02:25:32 INFO]:        at net.kyori.adventure.text.serializer.gson.GsonComponentSerializerImpl.deserialize(GsonComponentSerializerImpl.java:44) ~[Paper-Server-reobf.jar:git-Paper-"416ec98"]
```
An extra piece of information,
```json
[]
```
is not a valid component as expected, so accepting (and then ignoring) empty arrays is just a special case for Components in hoverEvents, not everywhere.

Changed files:
text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/StyleSerializer.java
text-serializer-gson/src/test/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerTest.java

diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/StyleSerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/StyleSerializer.java
index 4f74b016..5f692cb6 100644
--- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/StyleSerializer.java
+++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/StyleSerializer.java
@@ -147,7 +147,9 @@ final class StyleSerializer extends TypeAdapter<Style> {
             if (hoverEventObject.has(HOVER_EVENT_CONTENTS)) {
               final @Nullable JsonElement rawValue = hoverEventObject.get(HOVER_EVENT_CONTENTS);
               final Class<?> actionType = action.type();
-              if (SerializerFactory.COMPONENT_TYPE.isAssignableFrom(actionType)) {
+              if (isNullOrEmpty(rawValue)) {
+                value = null;
+              } else if (SerializerFactory.COMPONENT_TYPE.isAssignableFrom(actionType)) {
                 value = this.gson.fromJson(rawValue, SerializerFactory.COMPONENT_TYPE);
               } else if (SerializerFactory.SHOW_ITEM_TYPE.isAssignableFrom(actionType)) {
                 value = this.gson.fromJson(rawValue, SerializerFactory.SHOW_ITEM_TYPE);
@@ -157,8 +159,13 @@ final class StyleSerializer extends TypeAdapter<Style> {
                 value = null;
               }
             } else if (hoverEventObject.has(HOVER_EVENT_VALUE)) {
-              final Component rawValue = this.gson.fromJson(hoverEventObject.get(HOVER_EVENT_VALUE), SerializerFactory.COMPONENT_TYPE);
-              value = this.legacyHoverEventContents(action, rawValue);
+              final JsonElement element = hoverEventObject.get(HOVER_EVENT_VALUE);
+              if (isNullOrEmpty(element)) {
+                value = null;
+              } else {
+                final Component rawValue = this.gson.fromJson(element, SerializerFactory.COMPONENT_TYPE);
+                value = this.legacyHoverEventContents(action, rawValue);
+              }
             } else {
               value = null;
             }
@@ -177,6 +184,10 @@ final class StyleSerializer extends TypeAdapter<Style> {
     return style.build();
   }
 
+  private static boolean isNullOrEmpty(final @Nullable JsonElement element) {
+    return element == null || element.isJsonNull() || (element.isJsonArray() && element.getAsJsonArray().size() == 0) || (element.isJsonObject() && element.getAsJsonObject().size() == 0);
+  }
+
   private boolean readBoolean(final JsonReader in) throws IOException {
     final JsonToken peek = in.peek();
     if (peek == JsonToken.BOOLEAN) {
diff --git a/text-serializer-gson/src/test/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerTest.java b/text-serializer-gson/src/test/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerTest.java
index 7cad7c7c..db6f1416 100644
--- a/text-serializer-gson/src/test/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerTest.java
+++ b/text-serializer-gson/src/test/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerTest.java
@@ -90,6 +90,14 @@ class GsonComponentSerializerTest {
     assertEquals("Don't know how to turn null into a Component", ex.getMessage());
   }
 
+  // https://github.com/KyoriPowered/adventure/issues/414
+  @Test
+  void testSkipInvalidHoverEvent() {
+    final String input = "{\\"text\\": \\"hello\\", \\"hoverEvent\\":{\\"action\\":\\"show_text\\",\\"value\\":[]}}";
+    final Component expected = Component.text("hello");
+    assertEquals(expected, GsonComponentSerializer.gson().deserialize(input));
+  }
+
   private static String name(final NamedTextColor color) {
     return NamedTextColor.NAMES.key(color);
   }