From 40d21bbe24672b166ffbfd42baa8c0b9f3300aaf Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 2 Jun 2026 21:11:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=A0=E6=B3=95=E4=B8=BA?= =?UTF-8?q?=20MC=201.21.11=20=E5=AE=89=E8=A3=85=20Forge=20=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20(#6160)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hmcl/util/gson/InstantTypeAdapter.java | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/gson/InstantTypeAdapter.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/gson/InstantTypeAdapter.java index 82af720d97..4146c6bd61 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/gson/InstantTypeAdapter.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/gson/InstantTypeAdapter.java @@ -21,50 +21,81 @@ import com.google.gson.*; import java.lang.reflect.Type; import java.time.*; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.DateTimeParseException; -import java.time.format.FormatStyle; +import java.time.format.*; import java.time.temporal.ChronoUnit; import java.util.Locale; import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME; +import static java.time.temporal.ChronoField.*; +/// Serializes and deserializes [Instant] values for Gson. +/// +/// Serialized values are written as ISO offset date-time strings in the system default time zone, +/// truncated to whole seconds. Deserialization accepts the historical US localized date-time +/// format, ISO local date-time values with optional offsets, and ISO local date-time values +/// interpreted in the system default time zone. +/// +/// @author Glavo public final class InstantTypeAdapter implements JsonSerializer, JsonDeserializer { + /// Shared adapter instance for registering with Gson. public static final InstantTypeAdapter INSTANCE = new InstantTypeAdapter(); + /// Creates the singleton adapter instance. private InstantTypeAdapter() { } + /// Serializes an [Instant] to a JSON string in the system default time zone. + /// + /// @param t the instant to serialize + /// @param type the requested source type + /// @param jsc the Gson serialization context + /// @return a JSON primitive containing the serialized instant @Override public JsonElement serialize(Instant t, Type type, JsonSerializationContext jsc) { return new JsonPrimitive(serializeToString(t, ZoneId.systemDefault())); } + /// Deserializes a JSON string into an [Instant]. + /// + /// @param json the JSON element to deserialize + /// @param type the requested target type + /// @param context the Gson deserialization context + /// @return the parsed instant + /// @throws JsonParseException if `json` is not a string or cannot be parsed as an instant + /// @throws IllegalArgumentException if `type` is not [Instant] @Override public Instant deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { - if (!(json instanceof JsonPrimitive)) - throw new JsonParseException("The instant should be a string value"); - else { + if (json instanceof JsonPrimitive) { Instant time = deserializeToInstant(json.getAsString()); if (type == Instant.class) return time; else throw new IllegalArgumentException(this.getClass() + " cannot be deserialized to " + type); + } else { + throw new JsonParseException("The instant should be a string value"); } } + /// Formatter for the legacy US localized date-time representation. private static final DateTimeFormatter EN_US_FORMAT = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.MEDIUM) .withLocale(Locale.US) .withZone(ZoneId.systemDefault()); + + /// Formatter for ISO local date-time text followed by one of the supported offset forms. private static final DateTimeFormatter ISO_DATE_TIME = new DateTimeFormatterBuilder() .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME) .optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd() + .optionalStart().appendOffset("+H:MM", "+0:00").optionalEnd() .optionalStart().appendOffset("+HHMM", "+0000").optionalEnd() .optionalStart().appendOffset("+HH", "Z").optionalEnd() .optionalStart().appendOffsetId().optionalEnd() .toFormatter(); + /// Parses an instant from one of the supported textual representations. + /// + /// @param string the text to parse + /// @return the parsed instant + /// @throws JsonParseException if `string` is not in a supported instant format public static Instant deserializeToInstant(String string) { try { return ZonedDateTime.parse(string, EN_US_FORMAT).toInstant(); @@ -83,6 +114,13 @@ public final class InstantTypeAdapter implements JsonSerializer, JsonDe } } + /// Formats an instant as an ISO offset date-time string in the given time zone. + /// + /// The output is truncated to whole seconds. + /// + /// @param instant the instant to format + /// @param zone the time zone used to render the instant + /// @return the formatted instant public static String serializeToString(Instant instant, ZoneId zone) { return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.ofInstant(instant, zone).truncatedTo(ChronoUnit.SECONDS)); }