diff --git a/.checkstyle/suppressions.xml b/.checkstyle/suppressions.xml
index ea0de2320..7fd987d8e 100644
--- a/.checkstyle/suppressions.xml
+++ b/.checkstyle/suppressions.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/api/src/main/java/net/kyori/adventure/util/Services.java b/api/src/main/java/net/kyori/adventure/util/Services.java
index 038e47fbf..b1ca003be 100644
--- a/api/src/main/java/net/kyori/adventure/util/Services.java
+++ b/api/src/main/java/net/kyori/adventure/util/Services.java
@@ -69,4 +69,56 @@ private Services() {
}
return Optional.empty();
}
+
+ /**
+ * A fallback service.
+ *
+ *
When used in tandem with {@link #serviceWithFallback(Class)}, classes that implement this interface
+ * will be ignored in favour of classes that do not implement this interface.
+ *
+ * @since 4.14.0
+ */
+ public interface Fallback {
+ }
+
+ /**
+ * Locates a service.
+ *
+ * If multiple services of this type exist, the first non-fallback service will be returned.
+ *
+ * @param type the service type
+ * @param the service type
+ * @return a service, or {@link Optional#empty()}
+ * @see Fallback
+ * @since 4.14.0
+ */
+ public static
@NotNull Optional
serviceWithFallback(final @NotNull Class
type) {
+ final ServiceLoader
loader = Services0.loader(type);
+ final Iterator
it = loader.iterator();
+ P firstFallback = null;
+
+ while (it.hasNext()) {
+ final P instance;
+
+ try {
+ instance = it.next();
+ } catch (final Throwable t) {
+ if (SERVICE_LOAD_FAILURES_ARE_FATAL) {
+ throw new IllegalStateException("Encountered an exception loading service " + type, t);
+ } else {
+ continue;
+ }
+ }
+
+ if (instance instanceof Fallback) {
+ if (firstFallback == null) {
+ firstFallback = instance;
+ }
+ } else {
+ return Optional.of(instance);
+ }
+ }
+
+ return Optional.ofNullable(firstFallback);
+ }
}
diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts
index 38362c64f..758e0d5b3 100644
--- a/bom/build.gradle.kts
+++ b/bom/build.gradle.kts
@@ -23,7 +23,8 @@ dependencies {
"text-minimessage",
"text-serializer-ansi",
"text-serializer-gson",
- "text-serializer-gson-legacy-impl",
+ "text-serializer-json",
+ "text-serializer-json-legacy-impl",
"text-serializer-legacy",
"text-serializer-plain"
).forEach {
diff --git a/build-logic/src/main/kotlin/adventure.common-conventions.gradle.kts b/build-logic/src/main/kotlin/adventure.common-conventions.gradle.kts
index 631b7dbe9..76ccc27f0 100644
--- a/build-logic/src/main/kotlin/adventure.common-conventions.gradle.kts
+++ b/build-logic/src/main/kotlin/adventure.common-conventions.gradle.kts
@@ -3,7 +3,6 @@ import com.diffplug.gradle.spotless.FormatExtension
import me.champeau.jmh.JMHPlugin
import me.champeau.jmh.JmhParameters
import net.ltgt.gradle.errorprone.errorprone
-import org.gradle.api.artifacts.type.ArtifactTypeDefinition
plugins {
id("adventure.base-conventions")
diff --git a/build-logic/src/main/kotlin/adventure.json-impl-conventions.gradle.kts b/build-logic/src/main/kotlin/adventure.json-impl-conventions.gradle.kts
new file mode 100644
index 000000000..5cf02bde3
--- /dev/null
+++ b/build-logic/src/main/kotlin/adventure.json-impl-conventions.gradle.kts
@@ -0,0 +1,66 @@
+import me.champeau.jmh.JMHPlugin
+import me.champeau.jmh.JmhBytecodeGeneratorTask
+
+plugins {
+ id("adventure.common-conventions")
+}
+
+val sharedTests by configurations.registering {
+ isVisible = false
+ isCanBeResolved = false
+ isCanBeConsumed = false
+}
+
+val sharedTestDirs by configurations.registering {
+ isVisible = false
+ isCanBeConsumed = false
+ extendsFrom(sharedTests.get())
+ isTransitive = false // we want the directory on its own
+
+ attributes {
+ attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
+ attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_API)) // needs to be API to get the unpacked test-fixtures variant
+ attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
+ attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.CLASSES))
+ }
+}
+
+val sharedBenchmarks by configurations.registering {
+ isVisible = false
+ isTransitive = false
+
+ attributes {
+ attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
+ attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
+ attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
+ attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.CLASSES))
+ }
+}
+
+configurations.testRuntimeOnly {
+ extendsFrom(sharedTests.get())
+}
+
+tasks.test {
+ testClassesDirs += sharedTestDirs.get()
+}
+
+dependencies {
+ val textSerializerJson = project(":adventure-text-serializer-json")
+ api(textSerializerJson)
+ sharedTests.name(testFixtures(textSerializerJson.copy()))
+ sharedBenchmarks.name(textSerializerJson.copy().capabilities {
+ requireCapability("${project.group}:adventure-text-serializer-json-benchmarks:${project.version}")
+ })
+ annotationProcessor(project(":adventure-annotation-processors"))
+}
+
+// Configure benchmarks to read from json project
+plugins.withId("me.champeau.jmh") {
+ configurations.named(JMHPlugin.getJHM_RUNTIME_CLASSPATH_CONFIGURATION()) {
+ extendsFrom(sharedBenchmarks.get())
+ }
+ tasks.named("jmhRunBytecodeGenerator", JmhBytecodeGeneratorTask::class) {
+ classesDirsToProcess.from(sharedBenchmarks.get())
+ }
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 6e8875da9..031b4b2b3 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -43,6 +43,8 @@ sequenceOf(
"text-minimessage",
"text-serializer-gson",
"text-serializer-gson-legacy-impl",
+ "text-serializer-json",
+ "text-serializer-json-legacy-impl",
"text-serializer-legacy",
"text-serializer-plain",
"text-serializer-ansi",
diff --git a/text-serializer-gson-legacy-impl/build.gradle.kts b/text-serializer-gson-legacy-impl/build.gradle.kts
index ac5adbc5e..7718b6f04 100644
--- a/text-serializer-gson-legacy-impl/build.gradle.kts
+++ b/text-serializer-gson-legacy-impl/build.gradle.kts
@@ -3,9 +3,8 @@ plugins {
}
dependencies {
- api(projects.adventureApi)
api(projects.adventureTextSerializerGson)
- api(projects.adventureNbt)
+ api(projects.adventureTextSerializerJsonLegacyImpl)
}
applyJarMetadata("net.kyori.adventure.text.serializer.gson.legacyimpl")
diff --git a/text-serializer-gson-legacy-impl/src/main/java/net/kyori/adventure/text/serializer/gson/legacyimpl/NBTLegacyHoverEventSerializer.java b/text-serializer-gson-legacy-impl/src/main/java/net/kyori/adventure/text/serializer/gson/legacyimpl/NBTLegacyHoverEventSerializer.java
index 6065cbd6e..a9811f6e0 100644
--- a/text-serializer-gson-legacy-impl/src/main/java/net/kyori/adventure/text/serializer/gson/legacyimpl/NBTLegacyHoverEventSerializer.java
+++ b/text-serializer-gson-legacy-impl/src/main/java/net/kyori/adventure/text/serializer/gson/legacyimpl/NBTLegacyHoverEventSerializer.java
@@ -25,20 +25,27 @@
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.serializer.gson.LegacyHoverEventSerializer;
+import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* A legacy {@link HoverEvent} serializer.
*
* @since 4.3.0
+ * @deprecated for removal since 4.14, use {@link net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer the text-serializer-json version} instead.
*/
-public interface NBTLegacyHoverEventSerializer extends LegacyHoverEventSerializer {
+@Deprecated
+@ApiStatus.ScheduledForRemoval(inVersion = "5.0.0")
+public interface NBTLegacyHoverEventSerializer extends LegacyHoverEventSerializer, net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer {
/**
* Gets the legacy {@link HoverEvent} serializer.
*
* @return a legacy {@link HoverEvent} serializer
* @since 4.3.0
+ * @deprecated for removal since 4.14, use {@link net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer the text-serializer-json version} instead.
*/
+ @Deprecated
+ @ApiStatus.ScheduledForRemoval(inVersion = "5.0.0")
static @NotNull LegacyHoverEventSerializer get() {
return NBTLegacyHoverEventSerializerImpl.INSTANCE;
}
diff --git a/text-serializer-gson-legacy-impl/src/main/java/net/kyori/adventure/text/serializer/gson/legacyimpl/NBTLegacyHoverEventSerializerImpl.java b/text-serializer-gson-legacy-impl/src/main/java/net/kyori/adventure/text/serializer/gson/legacyimpl/NBTLegacyHoverEventSerializerImpl.java
index 4603d0ee0..d60ff7780 100644
--- a/text-serializer-gson-legacy-impl/src/main/java/net/kyori/adventure/text/serializer/gson/legacyimpl/NBTLegacyHoverEventSerializerImpl.java
+++ b/text-serializer-gson-legacy-impl/src/main/java/net/kyori/adventure/text/serializer/gson/legacyimpl/NBTLegacyHoverEventSerializerImpl.java
@@ -24,85 +24,39 @@
package net.kyori.adventure.text.serializer.gson.legacyimpl;
import java.io.IOException;
-import java.util.UUID;
-import net.kyori.adventure.key.Key;
-import net.kyori.adventure.nbt.CompoundBinaryTag;
-import net.kyori.adventure.nbt.TagStringIO;
-import net.kyori.adventure.nbt.api.BinaryTagHolder;
import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.serializer.gson.LegacyHoverEventSerializer;
+import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer;
import net.kyori.adventure.util.Codec;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+@Deprecated
final class NBTLegacyHoverEventSerializerImpl implements LegacyHoverEventSerializer {
static final NBTLegacyHoverEventSerializerImpl INSTANCE = new NBTLegacyHoverEventSerializerImpl();
- private static final TagStringIO SNBT_IO = TagStringIO.get();
- private static final Codec SNBT_CODEC = Codec.codec(SNBT_IO::asCompound, SNBT_IO::asString);
- static final String ITEM_TYPE = "id";
- static final String ITEM_COUNT = "Count";
- static final String ITEM_TAG = "tag";
-
- static final String ENTITY_NAME = "name";
- static final String ENTITY_TYPE = "type";
- static final String ENTITY_ID = "id";
+ static final net.kyori.adventure.text.serializer.json.LegacyHoverEventSerializer NEW_INSTANCE = NBTLegacyHoverEventSerializer.get();
private NBTLegacyHoverEventSerializerImpl() {
}
@Override
public HoverEvent.@NotNull ShowItem deserializeShowItem(final @NotNull Component input) throws IOException {
- assertTextComponent(input);
- final CompoundBinaryTag contents = SNBT_CODEC.decode(((TextComponent) input).content());
- final CompoundBinaryTag tag = contents.getCompound(ITEM_TAG);
- return HoverEvent.ShowItem.showItem(
- Key.key(contents.getString(ITEM_TYPE)),
- contents.getByte(ITEM_COUNT, (byte) 1),
- tag == CompoundBinaryTag.empty() ? null : BinaryTagHolder.encode(tag, SNBT_CODEC)
- );
+ return NEW_INSTANCE.deserializeShowItem(input);
}
@Override
public HoverEvent.@NotNull ShowEntity deserializeShowEntity(final @NotNull Component input, final Codec.Decoder componentCodec) throws IOException {
- assertTextComponent(input);
- final CompoundBinaryTag contents = SNBT_CODEC.decode(((TextComponent) input).content());
- return HoverEvent.ShowEntity.showEntity(
- Key.key(contents.getString(ENTITY_TYPE)),
- UUID.fromString(contents.getString(ENTITY_ID)),
- componentCodec.decode(contents.getString(ENTITY_NAME))
- );
- }
-
- private static void assertTextComponent(final Component component) {
- if (!(component instanceof TextComponent) || !component.children().isEmpty()) {
- throw new IllegalArgumentException("Legacy events must be single Component instances");
- }
+ return NEW_INSTANCE.deserializeShowEntity(input, componentCodec);
}
@Override
public @NotNull Component serializeShowItem(final HoverEvent.@NotNull ShowItem input) throws IOException {
- final CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
- .putString(ITEM_TYPE, input.item().asString())
- .putByte(ITEM_COUNT, (byte) input.count());
- final @Nullable BinaryTagHolder nbt = input.nbt();
- if (nbt != null) {
- builder.put(ITEM_TAG, nbt.get(SNBT_CODEC));
- }
- return Component.text(SNBT_CODEC.encode(builder.build()));
+ return NEW_INSTANCE.serializeShowItem(input);
}
@Override
public @NotNull Component serializeShowEntity(final HoverEvent.@NotNull ShowEntity input, final Codec.Encoder componentCodec) throws IOException {
- final CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
- .putString(ENTITY_ID, input.id().toString())
- .putString(ENTITY_TYPE, input.type().asString());
- final @Nullable Component name = input.name();
- if (name != null) {
- builder.putString(ENTITY_NAME, componentCodec.encode(name));
- }
- return Component.text(SNBT_CODEC.encode(builder.build()));
+ return NEW_INSTANCE.serializeShowEntity(input, componentCodec);
}
}
diff --git a/text-serializer-gson/build.gradle.kts b/text-serializer-gson/build.gradle.kts
index 04e83fd62..5d6c1935e 100644
--- a/text-serializer-gson/build.gradle.kts
+++ b/text-serializer-gson/build.gradle.kts
@@ -1,13 +1,10 @@
plugins {
- id("adventure.common-conventions")
+ id("adventure.json-impl-conventions")
alias(libs.plugins.jmh)
}
dependencies {
- api(projects.adventureApi)
api(libs.gson)
- testImplementation(projects.adventureNbt)
- annotationProcessor(projects.adventureAnnotationProcessors)
}
applyJarMetadata("net.kyori.adventure.text.serializer.gson")
diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ComponentSerializerImpl.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ComponentSerializerImpl.java
index 88a1d0ca3..b3bb27732 100644
--- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ComponentSerializerImpl.java
+++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ComponentSerializerImpl.java
@@ -53,25 +53,25 @@
import net.kyori.adventure.text.TranslatableComponent;
import org.jetbrains.annotations.Nullable;
-final class ComponentSerializerImpl extends TypeAdapter {
- static final String TEXT = "text";
- static final String TRANSLATE = "translate";
- static final String TRANSLATE_FALLBACK = "fallback";
- static final String TRANSLATE_WITH = "with";
- static final String SCORE = "score";
- static final String SCORE_NAME = "name";
- static final String SCORE_OBJECTIVE = "objective";
- static final String SCORE_VALUE = "value";
- static final String SELECTOR = "selector";
- static final String KEYBIND = "keybind";
- static final String EXTRA = "extra";
- static final String NBT = "nbt";
- static final String NBT_INTERPRET = "interpret";
- static final String NBT_BLOCK = "block";
- static final String NBT_ENTITY = "entity";
- static final String NBT_STORAGE = "storage";
- static final String SEPARATOR = "separator";
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.EXTRA;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.KEYBIND;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.NBT;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.NBT_BLOCK;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.NBT_ENTITY;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.NBT_INTERPRET;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.NBT_STORAGE;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SCORE;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SCORE_NAME;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SCORE_OBJECTIVE;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SCORE_VALUE;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SELECTOR;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SEPARATOR;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.TEXT;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.TRANSLATE;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.TRANSLATE_FALLBACK;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.TRANSLATE_WITH;
+final class ComponentSerializerImpl extends TypeAdapter {
static final Type COMPONENT_LIST_TYPE = new TypeToken>() {}.getType();
static TypeAdapter create(final Gson gson) {
diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializer.java
index 7290385ca..209bde6a4 100644
--- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializer.java
+++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializer.java
@@ -30,7 +30,7 @@
import java.util.function.UnaryOperator;
import net.kyori.adventure.builder.AbstractBuilder;
import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.serializer.ComponentSerializer;
+import net.kyori.adventure.text.serializer.json.JSONComponentSerializer;
import net.kyori.adventure.util.Buildable;
import net.kyori.adventure.util.PlatformAPI;
import org.jetbrains.annotations.ApiStatus;
@@ -40,12 +40,15 @@
/**
* A gson component serializer.
*
+ * This is a specific implementation of {@link JSONComponentSerializer} for the Gson library.
+ * Libraries that want to remain unopinionated should work with that interface instead.
+ *
* Use {@link Builder#downsampleColors()} to support platforms
* that do not understand hex colors that were introduced in Minecraft 1.16.
*
* @since 4.0.0
*/
-public interface GsonComponentSerializer extends ComponentSerializer, Buildable {
+public interface GsonComponentSerializer extends JSONComponentSerializer, Buildable {
/**
* Gets a component serializer for gson serialization and deserialization.
*
@@ -118,7 +121,7 @@ static Builder builder() {
*
* @since 4.0.0
*/
- interface Builder extends AbstractBuilder, Buildable.Builder {
+ interface Builder extends AbstractBuilder, Buildable.Builder, JSONComponentSerializer.Builder {
/**
* Sets that the serializer should downsample hex colors to named colors.
*
@@ -135,16 +138,19 @@ interface Builder extends AbstractBuilder, Buildable.Bu
* @param serializer serializer
* @return this builder
* @since 4.0.0
+ * @deprecated for removal since 4.14.0, use {@link #legacyHoverEventSerializer(net.kyori.adventure.text.serializer.json.LegacyHoverEventSerializer)} instead
*/
- @NotNull Builder legacyHoverEventSerializer(final @Nullable LegacyHoverEventSerializer serializer);
+ @Deprecated
+ default @NotNull Builder legacyHoverEventSerializer(final @Nullable LegacyHoverEventSerializer serializer) {
+ return this.legacyHoverEventSerializer((net.kyori.adventure.text.serializer.json.LegacyHoverEventSerializer) serializer);
+ }
+
+ @Override
+ @NotNull Builder legacyHoverEventSerializer(final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer serializer);
/**
- * Output a legacy hover event {@code value} in addition to the modern {@code contents}.
+ * {@inheritDoc}
*
- * A {@link #legacyHoverEventSerializer(LegacyHoverEventSerializer) legacy hover serializer} must also be set
- * to serialize any hover events beyond those with action {@link net.kyori.adventure.text.event.HoverEvent.Action#SHOW_TEXT}
- *
- * @return this builder
* @since 4.0.0
*/
@NotNull Builder emitLegacyHoverEvent();
diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerImpl.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerImpl.java
index a855bbe48..acf1b65f8 100644
--- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerImpl.java
+++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerImpl.java
@@ -55,10 +55,10 @@ static final class Instances {
private final Gson serializer;
private final UnaryOperator populator;
private final boolean downsampleColor;
- private final @Nullable LegacyHoverEventSerializer legacyHoverSerializer;
+ private final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer legacyHoverSerializer;
private final boolean emitLegacyHover;
- GsonComponentSerializerImpl(final boolean downsampleColor, final @Nullable LegacyHoverEventSerializer legacyHoverSerializer, final boolean emitLegacyHover) {
+ GsonComponentSerializerImpl(final boolean downsampleColor, final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer legacyHoverSerializer, final boolean emitLegacyHover) {
this.downsampleColor = downsampleColor;
this.legacyHoverSerializer = legacyHoverSerializer;
this.emitLegacyHover = emitLegacyHover;
@@ -121,7 +121,7 @@ static final class Instances {
static final class BuilderImpl implements Builder {
private boolean downsampleColor = false;
- private @Nullable LegacyHoverEventSerializer legacyHoverSerializer;
+ private net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer legacyHoverSerializer;
private boolean emitLegacyHover = false;
BuilderImpl() {
@@ -142,7 +142,7 @@ static final class BuilderImpl implements Builder {
}
@Override
- public @NotNull Builder legacyHoverEventSerializer(final @Nullable LegacyHoverEventSerializer serializer) {
+ public @NotNull Builder legacyHoverEventSerializer(final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer serializer) {
this.legacyHoverSerializer = serializer;
return this;
}
diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/JSONComponentSerializerProviderImpl.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/JSONComponentSerializerProviderImpl.java
new file mode 100644
index 000000000..346084a2e
--- /dev/null
+++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/JSONComponentSerializerProviderImpl.java
@@ -0,0 +1,48 @@
+/*
+ * This file is part of adventure, licensed under the MIT License.
+ *
+ * Copyright (c) 2017-2023 KyoriPowered
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package net.kyori.adventure.text.serializer.gson;
+
+import java.util.function.Supplier;
+import net.kyori.adventure.text.serializer.json.JSONComponentSerializer;
+import net.kyori.adventure.util.Services;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Implementation of the JSON component serializer provider.
+ *
+ * @since 4.14.0
+ */
+@ApiStatus.Internal
+public final class JSONComponentSerializerProviderImpl implements JSONComponentSerializer.Provider, Services.Fallback {
+ @Override
+ public @NotNull JSONComponentSerializer json() {
+ return GsonComponentSerializer.gson();
+ }
+
+ @Override
+ public @NotNull Supplier builder() {
+ return GsonComponentSerializer::builder;
+ }
+}
diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/LegacyHoverEventSerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/LegacyHoverEventSerializer.java
index 73ffffb68..ca7479f1c 100644
--- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/LegacyHoverEventSerializer.java
+++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/LegacyHoverEventSerializer.java
@@ -23,57 +23,16 @@
*/
package net.kyori.adventure.text.serializer.gson;
-import java.io.IOException;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.event.HoverEvent;
-import net.kyori.adventure.util.Codec;
-import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.ApiStatus;
/**
* Adapter to convert between modern and legacy hover event formats.
*
* @since 4.0.0
+ * @deprecated for removal since 4.13.0, implement {@link net.kyori.adventure.text.serializer.json.LegacyHoverEventSerializer} instead
*/
-public interface LegacyHoverEventSerializer {
- /**
- * Convert a legacy hover event {@code show_item} value to its modern format.
- *
- * @param input component whose plain-text value is a SNBT string
- * @return the deserialized event
- * @throws IOException if the input is improperly formatted
- * @since 4.0.0
- */
- HoverEvent.@NotNull ShowItem deserializeShowItem(final @NotNull Component input) throws IOException;
+@Deprecated
+@ApiStatus.ScheduledForRemoval(inVersion = "5.0.0")
+public interface LegacyHoverEventSerializer extends net.kyori.adventure.text.serializer.json.LegacyHoverEventSerializer {
- /**
- * Convert a legacy hover event {@code show_entity} value to its modern format.
- *
- * @param input component whose plain-text value is a SNBT string
- * @param componentDecoder A decoder that can take a JSON string and return a deserialized component
- * @return the deserialized event
- * @throws IOException if the input is improperly formatted
- * @since 4.0.0
- */
- HoverEvent.@NotNull ShowEntity deserializeShowEntity(final @NotNull Component input, final Codec.Decoder componentDecoder) throws IOException;
-
- /**
- * Convert a modern hover event {@code show_item} value to its legacy format.
- *
- * @param input modern hover event
- * @return component with the legacy value as a SNBT string
- * @throws IOException if the input is improperly formatted
- * @since 4.0.0
- */
- @NotNull Component serializeShowItem(final HoverEvent.@NotNull ShowItem input) throws IOException;
-
- /**
- * Convert a modern hover event {@code show_entity} value to its legacy format.
- *
- * @param input modern hover event
- * @param componentEncoder An encoder that can take a {@link Component} and return a JSON string
- * @return component with the legacy value as a SNBT string
- * @throws IOException if the input is improperly formatted
- * @since 4.0.0
- */
- @NotNull Component serializeShowEntity(final HoverEvent.@NotNull ShowEntity input, final Codec.Encoder componentEncoder) throws IOException;
}
diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/SerializerFactory.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/SerializerFactory.java
index b47be5e0a..e644cf7ea 100644
--- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/SerializerFactory.java
+++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/SerializerFactory.java
@@ -51,10 +51,10 @@ final class SerializerFactory implements TypeAdapterFactory {
static final Class BLOCK_NBT_POS_TYPE = BlockNBTComponent.Pos.class;
private final boolean downsampleColors;
- private final LegacyHoverEventSerializer legacyHoverSerializer;
+ private final net.kyori.adventure.text.serializer.json.LegacyHoverEventSerializer legacyHoverSerializer;
private final boolean emitLegacyHover;
- SerializerFactory(final boolean downsampleColors, final @Nullable LegacyHoverEventSerializer legacyHoverSerializer, final boolean emitLegacyHover) {
+ SerializerFactory(final boolean downsampleColors, final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer legacyHoverSerializer, final boolean emitLegacyHover) {
this.downsampleColors = downsampleColors;
this.legacyHoverSerializer = legacyHoverSerializer;
this.emitLegacyHover = emitLegacyHover;
diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowEntitySerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowEntitySerializer.java
index b8947beaa..bcd9b72c0 100644
--- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowEntitySerializer.java
+++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowEntitySerializer.java
@@ -35,11 +35,11 @@
import net.kyori.adventure.text.event.HoverEvent;
import org.jetbrains.annotations.Nullable;
-final class ShowEntitySerializer extends TypeAdapter {
- static final String TYPE = "type";
- static final String ID = "id";
- static final String NAME = "name";
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ENTITY_ID;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ENTITY_NAME;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ENTITY_TYPE;
+final class ShowEntitySerializer extends TypeAdapter {
static TypeAdapter create(final Gson gson) {
return new ShowEntitySerializer(gson).nullSafe();
}
@@ -60,11 +60,11 @@ public HoverEvent.ShowEntity read(final JsonReader in) throws IOException {
while (in.hasNext()) {
final String fieldName = in.nextName();
- if (fieldName.equals(TYPE)) {
+ if (fieldName.equals(SHOW_ENTITY_TYPE)) {
type = this.gson.fromJson(in, SerializerFactory.KEY_TYPE);
- } else if (fieldName.equals(ID)) {
+ } else if (fieldName.equals(SHOW_ENTITY_ID)) {
id = UUID.fromString(in.nextString());
- } else if (fieldName.equals(NAME)) {
+ } else if (fieldName.equals(SHOW_ENTITY_NAME)) {
name = this.gson.fromJson(in, SerializerFactory.COMPONENT_TYPE);
} else {
in.skipValue();
@@ -83,15 +83,15 @@ public HoverEvent.ShowEntity read(final JsonReader in) throws IOException {
public void write(final JsonWriter out, final HoverEvent.ShowEntity value) throws IOException {
out.beginObject();
- out.name(TYPE);
+ out.name(SHOW_ENTITY_TYPE);
this.gson.toJson(value.type(), SerializerFactory.KEY_TYPE, out);
- out.name(ID);
+ out.name(SHOW_ENTITY_ID);
out.value(value.id().toString());
final @Nullable Component name = value.name();
if (name != null) {
- out.name(NAME);
+ out.name(SHOW_ENTITY_NAME);
this.gson.toJson(name, SerializerFactory.COMPONENT_TYPE, out);
}
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 f243c063a..180db185a 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
@@ -35,11 +35,11 @@
import net.kyori.adventure.text.event.HoverEvent;
import org.jetbrains.annotations.Nullable;
-final class ShowItemSerializer extends TypeAdapter {
- static final String ID = "id";
- static final String COUNT = "count";
- static final String TAG = "tag";
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ITEM_COUNT;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ITEM_ID;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ITEM_TAG;
+final class ShowItemSerializer extends TypeAdapter {
static TypeAdapter create(final Gson gson) {
return new ShowItemSerializer(gson).nullSafe();
}
@@ -60,11 +60,11 @@ public HoverEvent.ShowItem read(final JsonReader in) throws IOException {
while (in.hasNext()) {
final String fieldName = in.nextName();
- if (fieldName.equals(ID)) {
+ if (fieldName.equals(SHOW_ITEM_ID)) {
key = this.gson.fromJson(in, SerializerFactory.KEY_TYPE);
- } else if (fieldName.equals(COUNT)) {
+ } else if (fieldName.equals(SHOW_ITEM_COUNT)) {
count = in.nextInt();
- } else if (fieldName.equals(TAG)) {
+ } else if (fieldName.equals(SHOW_ITEM_TAG)) {
final JsonToken token = in.peek();
if (token == JsonToken.STRING || token == JsonToken.NUMBER) {
nbt = BinaryTagHolder.binaryTagHolder(in.nextString());
@@ -73,7 +73,7 @@ public HoverEvent.ShowItem read(final JsonReader in) throws IOException {
} else if (token == JsonToken.NULL) {
in.nextNull();
} else {
- throw new JsonParseException("Expected " + TAG + " to be a string");
+ throw new JsonParseException("Expected " + SHOW_ITEM_TAG + " to be a string");
}
} else {
in.skipValue();
@@ -92,18 +92,18 @@ public HoverEvent.ShowItem read(final JsonReader in) throws IOException {
public void write(final JsonWriter out, final HoverEvent.ShowItem value) throws IOException {
out.beginObject();
- out.name(ID);
+ out.name(SHOW_ITEM_ID);
this.gson.toJson(value.item(), SerializerFactory.KEY_TYPE, out);
final int count = value.count();
if (count != 1) {
- out.name(COUNT);
+ out.name(SHOW_ITEM_COUNT);
out.value(count);
}
final @Nullable BinaryTagHolder nbt = value.nbt();
if (nbt != null) {
- out.name(TAG);
+ out.name(SHOW_ITEM_TAG);
out.value(nbt.string());
}
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 5f692cb69..4b385785f 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
@@ -46,6 +46,17 @@
import net.kyori.adventure.util.Codec;
import org.jetbrains.annotations.Nullable;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.CLICK_EVENT;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.CLICK_EVENT_ACTION;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.CLICK_EVENT_VALUE;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.COLOR;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.FONT;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.HOVER_EVENT;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.HOVER_EVENT_ACTION;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.HOVER_EVENT_CONTENTS;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.HOVER_EVENT_VALUE;
+import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.INSERTION;
+
final class StyleSerializer extends TypeAdapter