From 360350d44eeaa019ad95920feace75dd7cec45d0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 26 Jun 2024 12:49:42 -0400 Subject: [PATCH] Work around older Gson versions without record support --- bootstrap/spigot/build.gradle.kts | 3 +++ core/build.gradle.kts | 6 ++++- .../java/org/geysermc/geyser/GeyserImpl.java | 27 +++++++++++++++---- .../pack/GeyserResourcePackManifest.java | 2 ++ .../registry/loader/ResourcePackLoader.java | 7 +---- .../org/geysermc/geyser/util/FileUtils.java | 14 +++++----- .../org/geysermc/geyser/util/JsonUtils.java | 19 +++++++++++++ gradle/libs.versions.toml | 1 + 8 files changed, 60 insertions(+), 19 deletions(-) diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index fa24f3566..1f637d8f8 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -25,6 +25,8 @@ dependencies { compileOnly(libs.paper.mojangapi) compileOnlyApi(libs.viaversion) + + implementation(libs.gson.record.factory) // For 1.16.5/1.17.1 } platformRelocate("it.unimi.dsi.fastutil") @@ -36,6 +38,7 @@ platformRelocate("me.lucko.commodore") platformRelocate("org.yaml") // Broken as of 1.20 platformRelocate("org.spongepowered") platformRelocate("io.leangen.geantyref") +platformRelocate("marcono1234.gson") // These dependencies are already present on the platform provided(libs.viaversion) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 41a2b1ff0..1e5a9d675 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -20,6 +20,10 @@ dependencies { implementation(libs.configurate.yaml) api(libs.guava) + compileOnly(libs.gson.record.factory) { + isTransitive = false + } + // Fastutil Maps implementation(libs.bundles.fastutil) @@ -61,7 +65,7 @@ dependencies { // Test testImplementation(libs.junit) - testImplementation(libs.gson.runtime) + testImplementation(libs.gson.runtime) // Record support // Annotation Processors compileOnly(projects.ap) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index bbe6a34aa..c8fc94ffb 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -29,7 +29,6 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import io.netty.channel.epoll.Epoll; import io.netty.util.NettyRuntime; @@ -57,7 +56,11 @@ import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.command.CommandSource; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.event.EventRegistrar; -import org.geysermc.geyser.api.event.lifecycle.*; +import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserPostReloadEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserPreInitializeEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserPreReloadEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.BedrockListener; import org.geysermc.geyser.api.network.RemoteServer; @@ -87,7 +90,14 @@ import org.geysermc.geyser.skin.SkinProvider; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.*; +import org.geysermc.geyser.util.AssetUtils; +import org.geysermc.geyser.util.CooldownUtils; +import org.geysermc.geyser.util.DimensionUtils; +import org.geysermc.geyser.util.JsonUtils; +import org.geysermc.geyser.util.Metrics; +import org.geysermc.geyser.util.NewsHandler; +import org.geysermc.geyser.util.VersionCheckUtils; +import org.geysermc.geyser.util.WebUtils; import org.geysermc.mcprotocollib.network.tcp.TcpSession; import java.io.File; @@ -101,7 +111,14 @@ import java.net.UnknownHostException; import java.nio.file.Path; import java.security.Key; import java.text.DecimalFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; @@ -118,7 +135,7 @@ public class GeyserImpl implements GeyserApi { .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES) .enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES); - public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + public static final Gson GSON = JsonUtils.createGson(); public static final String NAME = "Geyser"; public static final String GIT_VERSION = BuildData.GIT_VERSION; diff --git a/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java b/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java index 2954a4454..582744c83 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java +++ b/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java @@ -30,6 +30,7 @@ import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; +import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.pack.ResourcePackManifest; @@ -46,6 +47,7 @@ public record GeyserResourcePackManifest(@SerializedName("format_version") int f public record Dependency(UUID uuid, Version version) implements ResourcePackManifest.Dependency { } + @JsonAdapter(value = Version.VersionDeserializer.class) public record Version(int major, int minor, int patch) implements ResourcePackManifest.Version { @Override diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java index 537c41ed9..800a3d22c 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.registry.loader; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.lifecycle.GeyserLoadResourcePacksEvent; import org.geysermc.geyser.api.pack.ResourcePack; @@ -57,9 +55,6 @@ import java.util.zip.ZipFile; * Loads {@link ResourcePack}s within a {@link Path} directory, firing the {@link GeyserLoadResourcePacksEvent}. */ public class ResourcePackLoader implements RegistryLoader> { - private static final Gson GSON = new GsonBuilder() - .registerTypeAdapter(GeyserResourcePackManifest.Version.class, new GeyserResourcePackManifest.Version.VersionDeserializer()) - .create(); static final PathMatcher PACK_MATCHER = FileSystems.getDefault().getPathMatcher("glob:**.{zip,mcpack}"); @@ -140,7 +135,7 @@ public class ResourcePackLoader implements RegistryLoader T loadJson(InputStream src, Class valueType) { - return loadJson(GeyserImpl.GSON, src, valueType); - } - - public static T loadJson(Gson gson, InputStream src, Class valueType) { // Read specifically with UTF-8 to allow any non-UTF-encoded JSON to read - return gson.fromJson(new InputStreamReader(src, StandardCharsets.UTF_8), valueType); + return GeyserImpl.GSON.fromJson(new InputStreamReader(src, StandardCharsets.UTF_8), valueType); } /** diff --git a/core/src/main/java/org/geysermc/geyser/util/JsonUtils.java b/core/src/main/java/org/geysermc/geyser/util/JsonUtils.java index 9ae74b177..a1f11e860 100644 --- a/core/src/main/java/org/geysermc/geyser/util/JsonUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/JsonUtils.java @@ -25,9 +25,13 @@ package org.geysermc.geyser.util; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import marcono1234.gson.recordadapter.RecordTypeAdapterFactory; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.pack.GeyserResourcePackManifest; import java.io.InputStream; import java.io.InputStreamReader; @@ -48,6 +52,21 @@ public final class JsonUtils { return GeyserImpl.GSON.fromJson(new InputStreamReader(stream), type); } + public static Gson createGson() { + GsonBuilder builder = new GsonBuilder().setPrettyPrinting(); + try { + new Gson().fromJson("{\"version\":[1,0,0],\"uuid\":\"eebb4ea8-a701-11eb-95ba-047d7bb283ba\"}", GeyserResourcePackManifest.Dependency.class); + } catch (Throwable e) { + // 1.16.5 and 1.17.1 (at minimum) have an outdated Gson version that doesn't support records. + // Remove this workaround when all platforms support Gson 2.10+ + // (Explicitly allow missing component values - the dependencies module for resource packs, for example, can be missing) + builder.registerTypeAdapterFactory(RecordTypeAdapterFactory.builder().allowMissingComponentValues().create()) + // Since this is a record, the above will take precedence unless we explicitly declare it. + .registerTypeAdapter(GeyserResourcePackManifest.Version.class, new GeyserResourcePackManifest.Version.VersionDeserializer()); + } + return builder.create(); + } + private JsonUtils() { } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f57cf79de..f5ceb1605 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -113,6 +113,7 @@ commodore = { group = "me.lucko", name = "commodore", version.ref = "commodore" guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } gson-runtime = { group = "com.google.code.gson", name = "gson", version.ref = "gson-runtime" } +gson-record-factory = { group = "com.github.Marcono1234", name = "gson-record-type-adapter-factory", version = "0.3.0" } junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotocollib" }