使用 TypeToken 替代 Type (#3320)

This commit is contained in:
Glavo
2024-10-11 20:50:58 +08:00
committed by GitHub
parent 541f2e2619
commit ef9159666c
34 changed files with 165 additions and 139 deletions

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.game; package org.jackhuang.hmcl.game;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.mod.MinecraftInstanceTask; import org.jackhuang.hmcl.mod.MinecraftInstanceTask;
@@ -67,8 +66,7 @@ public final class HMCLModpackInstallTask extends Task<Void> {
ModpackConfiguration<Modpack> config = null; ModpackConfiguration<Modpack> config = null;
try { try {
if (json.exists()) { if (json.exists()) {
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<Modpack>>() { config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(Modpack.class));
}.getType());
if (!HMCLModpackProvider.INSTANCE.getName().equals(config.getType())) if (!HMCLModpackProvider.INSTANCE.getName().equals(config.getType()))
throw new IllegalArgumentException("Version " + name + " is not a HMCL modpack. Cannot update this version."); throw new IllegalArgumentException("Version " + name + " is not a HMCL modpack. Cannot update this version.");

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.game; package org.jackhuang.hmcl.game;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.compress.archivers.zip.ZipFile; import org.apache.commons.compress.archivers.zip.ZipFile;
import org.jackhuang.hmcl.mod.*; import org.jackhuang.hmcl.mod.*;
import org.jackhuang.hmcl.mod.curse.CurseModpackProvider; import org.jackhuang.hmcl.mod.curse.CurseModpackProvider;
@@ -141,8 +140,7 @@ public final class ModpackHelper {
throw new FileNotFoundException(file.getPath()); throw new FileNotFoundException(file.getPath());
else else
try { try {
return JsonUtils.GSON.fromJson(FileUtils.readText(file), new TypeToken<ModpackConfiguration<?>>() { return JsonUtils.GSON.fromJson(FileUtils.readText(file), ModpackConfiguration.class);
}.getType());
} catch (JsonParseException e) { } catch (JsonParseException e) {
throw new IOException("Malformed modpack configuration"); throw new IOException("Malformed modpack configuration");
} }

View File

@@ -19,7 +19,6 @@ package org.jackhuang.hmcl.java;
import com.google.gson.*; import com.google.gson.*;
import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.JsonAdapter;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.Platform; import org.jackhuang.hmcl.util.platform.Platform;
@@ -29,6 +28,8 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import static org.jackhuang.hmcl.util.gson.JsonUtils.mapTypeOf;
/** /**
* @author Glavo * @author Glavo
*/ */
@@ -63,8 +64,7 @@ public final class JavaManifest {
public static final class Serializer implements JsonSerializer<JavaManifest>, JsonDeserializer<JavaManifest> { public static final class Serializer implements JsonSerializer<JavaManifest>, JsonDeserializer<JavaManifest> {
private static final Type LOCAL_FILES_TYPE = new TypeToken<Map<String, JavaLocalFiles.Local>>() { private static final Type LOCAL_FILES_TYPE = mapTypeOf(String.class, JavaLocalFiles.Local.class).getType();
}.getType();
@Override @Override
public JsonElement serialize(JavaManifest src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(JavaManifest src, Type typeOfSrc, JsonSerializationContext context) {

View File

@@ -17,7 +17,6 @@
*/ */
package org.jackhuang.hmcl.setting; package org.jackhuang.hmcl.setting;
import com.google.gson.reflect.TypeToken;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
@@ -55,6 +54,8 @@ import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
import static org.jackhuang.hmcl.util.Lang.immutableListOf; import static org.jackhuang.hmcl.util.Lang.immutableListOf;
import static org.jackhuang.hmcl.util.Lang.mapOf; import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
import static org.jackhuang.hmcl.util.gson.JsonUtils.mapTypeOf;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.logging.Logger.LOG;
@@ -171,14 +172,11 @@ public final class Accounts {
config().getAccountStorages().setAll(portable); config().getAccountStorages().setAll(portable);
} }
@SuppressWarnings("unchecked")
private static void loadGlobalAccountStorages() { private static void loadGlobalAccountStorages() {
Path globalAccountsFile = Metadata.HMCL_DIRECTORY.resolve("accounts.json"); Path globalAccountsFile = Metadata.HMCL_DIRECTORY.resolve("accounts.json");
if (Files.exists(globalAccountsFile)) { if (Files.exists(globalAccountsFile)) {
try (Reader reader = Files.newBufferedReader(globalAccountsFile)) { try (Reader reader = Files.newBufferedReader(globalAccountsFile)) {
globalAccountStorages.setAll((List<Map<Object, Object>>) globalAccountStorages.setAll(Config.CONFIG_GSON.fromJson(reader, listTypeOf(mapTypeOf(Object.class, Object.class))));
Config.CONFIG_GSON.fromJson(reader, new TypeToken<List<Map<Object, Object>>>() {
}.getType()));
} catch (Throwable e) { } catch (Throwable e) {
LOG.warning("Failed to load global accounts", e); LOG.warning("Failed to load global accounts", e);
} }

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.ui.main; package org.jackhuang.hmcl.ui.main;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
@@ -34,6 +33,7 @@ import org.jackhuang.hmcl.util.io.HttpRequest;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class HelpPage extends SpinnerPane { public class HelpPage extends SpinnerPane {
@@ -63,8 +63,7 @@ public class HelpPage extends SpinnerPane {
private void loadHelp() { private void loadHelp() {
showSpinner(); showSpinner();
Task.<List<HelpCategory>>supplyAsync(() -> HttpRequest.GET("https://docs.hmcl.net/index.json").getJson(new TypeToken<List<HelpCategory>>() { Task.supplyAsync(() -> HttpRequest.GET("https://docs.hmcl.net/index.json").getJson(listTypeOf(HelpCategory.class)))
}.getType()))
.thenAcceptAsync(Schedulers.javafx(), helpCategories -> { .thenAcceptAsync(Schedulers.javafx(), helpCategories -> {
for (HelpCategory category : helpCategories) { for (HelpCategory category : helpCategories) {
ComponentList categoryPane = new ComponentList(); ComponentList categoryPane = new ComponentList();

View File

@@ -17,7 +17,6 @@
*/ */
package org.jackhuang.hmcl.util; package org.jackhuang.hmcl.util;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.game.*;
import org.jackhuang.hmcl.setting.VersionSetting; import org.jackhuang.hmcl.setting.VersionSetting;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
@@ -34,6 +33,7 @@ import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.gson.JsonUtils.mapTypeOf;
import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/** /**
@@ -51,9 +51,7 @@ public final class NativePatcher {
return natives.computeIfAbsent(platform, p -> { return natives.computeIfAbsent(platform, p -> {
//noinspection ConstantConditions //noinspection ConstantConditions
try (Reader reader = new InputStreamReader(NativePatcher.class.getResourceAsStream("/assets/natives.json"), StandardCharsets.UTF_8)) { try (Reader reader = new InputStreamReader(NativePatcher.class.getResourceAsStream("/assets/natives.json"), StandardCharsets.UTF_8)) {
Map<String, Map<String, Library>> natives = JsonUtils.GSON.fromJson(reader, new TypeToken<Map<String, Map<String, Library>>>() { Map<String, Map<String, Library>> natives = JsonUtils.GSON.fromJson(reader, mapTypeOf(String.class, mapTypeOf(String.class, Library.class)));
}.getType());
return natives.getOrDefault(p.toString(), Collections.emptyMap()); return natives.getOrDefault(p.toString(), Collections.emptyMap());
} catch (IOException e) { } catch (IOException e) {
LOG.warning("Failed to load native library list", e); LOG.warning("Failed to load native library list", e);

View File

@@ -41,10 +41,9 @@
*/ */
package org.jackhuang.hmcl.util; package org.jackhuang.hmcl.util;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.Main; import org.jackhuang.hmcl.Main;
import org.jackhuang.hmcl.ui.SwingUtils; import org.jackhuang.hmcl.ui.SwingUtils;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.ChecksumMismatchException; import org.jackhuang.hmcl.util.io.ChecksumMismatchException;
import org.jackhuang.hmcl.util.io.IOUtils; import org.jackhuang.hmcl.util.io.IOUtils;
import org.jackhuang.hmcl.util.io.JarUtils; import org.jackhuang.hmcl.util.io.JarUtils;
@@ -68,6 +67,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toSet; import static java.util.stream.Collectors.toSet;
import static org.jackhuang.hmcl.Metadata.HMCL_DIRECTORY; import static org.jackhuang.hmcl.Metadata.HMCL_DIRECTORY;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
import static org.jackhuang.hmcl.util.gson.JsonUtils.mapTypeOf;
import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -104,11 +105,11 @@ public final class SelfDependencyPatcher {
private static final Path DEPENDENCIES_DIR_PATH = HMCL_DIRECTORY.resolve("dependencies").resolve(Platform.getPlatform().toString()).resolve("openjfx"); private static final Path DEPENDENCIES_DIR_PATH = HMCL_DIRECTORY.resolve("dependencies").resolve(Platform.getPlatform().toString()).resolve("openjfx");
static List<DependencyDescriptor> readDependencies() { static List<DependencyDescriptor> readDependencies() {
ArrayList<DependencyDescriptor> dependencies; List<DependencyDescriptor> dependencies;
//noinspection ConstantConditions //noinspection ConstantConditions
try (Reader reader = new InputStreamReader(SelfDependencyPatcher.class.getResourceAsStream(DEPENDENCIES_LIST_FILE), UTF_8)) { try (Reader reader = new InputStreamReader(SelfDependencyPatcher.class.getResourceAsStream(DEPENDENCIES_LIST_FILE), UTF_8)) {
Map<String, ArrayList<DependencyDescriptor>> allDependencies = Map<String, List<DependencyDescriptor>> allDependencies =
new Gson().fromJson(reader, new TypeToken<Map<String, ArrayList<DependencyDescriptor>>>(){}.getType()); JsonUtils.GSON.fromJson(reader, mapTypeOf(String.class, listTypeOf(DependencyDescriptor.class)));
dependencies = allDependencies.get(Platform.getPlatform().toString()); dependencies = allDependencies.get(Platform.getPlatform().toString());
} catch (IOException e) { } catch (IOException e) {
throw new UncheckedIOException(e); throw new UncheckedIOException(e);

View File

@@ -17,7 +17,6 @@
*/ */
package org.jackhuang.hmcl.auth.offline; package org.jackhuang.hmcl.auth.offline;
import com.google.gson.reflect.TypeToken;
import org.glavo.png.javafx.PNGJavaFXUtils; import org.glavo.png.javafx.PNGJavaFXUtils;
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile; import org.jackhuang.hmcl.auth.yggdrasil.GameProfile;
import org.jackhuang.hmcl.auth.yggdrasil.TextureModel; import org.jackhuang.hmcl.auth.yggdrasil.TextureModel;
@@ -38,6 +37,7 @@ import java.util.stream.Stream;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import static org.jackhuang.hmcl.util.Lang.mapOf; import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
public class YggdrasilServer extends HttpServer { public class YggdrasilServer extends HttpServer {
@@ -81,8 +81,7 @@ public class YggdrasilServer extends HttpServer {
} }
private Response profiles(Request request) throws IOException { private Response profiles(Request request) throws IOException {
List<String> names = JsonUtils.fromNonNullJsonFully(request.getSession().getInputStream(), new TypeToken<List<String>>() { List<String> names = JsonUtils.fromNonNullJsonFully(request.getSession().getInputStream(), listTypeOf(String.class));
}.getType());
return ok(names.stream().distinct() return ok(names.stream().distinct()
.map(this::findCharacterByName) .map(this::findCharacterByName)
.flatMap(Lang::toStream) .flatMap(Lang::toStream)

View File

@@ -17,7 +17,6 @@
*/ */
package org.jackhuang.hmcl.download.fabric; package org.jackhuang.hmcl.download.fabric;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.download.VersionList; import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
@@ -25,13 +24,13 @@ import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.Lang.wrap; import static org.jackhuang.hmcl.util.Lang.wrap;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
public final class FabricVersionList extends VersionList<FabricRemoteVersion> { public final class FabricVersionList extends VersionList<FabricRemoteVersion> {
private final DownloadProvider downloadProvider; private final DownloadProvider downloadProvider;
@@ -69,8 +68,8 @@ public final class FabricVersionList extends VersionList<FabricRemoteVersion> {
private List<String> getGameVersions(String metaUrl) throws IOException { private List<String> getGameVersions(String metaUrl) throws IOException {
String json = NetworkUtils.doGet(downloadProvider.injectURLWithCandidates(metaUrl)); String json = NetworkUtils.doGet(downloadProvider.injectURLWithCandidates(metaUrl));
return JsonUtils.GSON.<ArrayList<GameVersion>>fromJson(json, new TypeToken<ArrayList<GameVersion>>() { return JsonUtils.GSON.fromJson(json, listTypeOf(GameVersion.class))
}.getType()).stream().map(GameVersion::getVersion).collect(Collectors.toList()); .stream().map(GameVersion::getVersion).collect(Collectors.toList());
} }
private static String getLaunchMetaUrl(String gameVersion, String loaderVersion) { private static String getLaunchMetaUrl(String gameVersion, String loaderVersion) {

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.download.forge; package org.jackhuang.hmcl.download.forge;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.VersionList; import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.Immutable;
import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Lang;
@@ -40,6 +39,7 @@ import java.util.concurrent.CompletableFuture;
import static org.jackhuang.hmcl.util.Lang.mapOf; import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Lang.wrap; import static org.jackhuang.hmcl.util.Lang.wrap;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public final class ForgeBMCLVersionList extends VersionList<ForgeRemoteVersion> { public final class ForgeBMCLVersionList extends VersionList<ForgeRemoteVersion> {
@@ -87,11 +87,9 @@ public final class ForgeBMCLVersionList extends VersionList<ForgeRemoteVersion>
String lookupVersion = toLookupVersion(gameVersion); String lookupVersion = toLookupVersion(gameVersion);
return CompletableFuture.completedFuture(null) return CompletableFuture.completedFuture(null)
.thenApplyAsync(wrap(unused -> HttpRequest.GET(apiRoot + "/forge/minecraft/" + lookupVersion).<List<ForgeVersion>>getJson(new TypeToken<List<ForgeVersion>>() { .thenApplyAsync(wrap(unused -> HttpRequest.GET(apiRoot + "/forge/minecraft/" + lookupVersion).getJson(listTypeOf(ForgeVersion.class))))
}.getType())))
.thenAcceptAsync(forgeVersions -> { .thenAcceptAsync(forgeVersions -> {
lock.writeLock().lock(); lock.writeLock().lock();
try { try {
versions.clear(gameVersion); versions.clear(gameVersion);
if (forgeVersions == null) return; if (forgeVersions == null) return;

View File

@@ -19,7 +19,6 @@ package org.jackhuang.hmcl.download.java.mojang;
import com.google.gson.*; import com.google.gson.*;
import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.JsonAdapter;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.game.DownloadInfo; import org.jackhuang.hmcl.game.DownloadInfo;
import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.Immutable;
@@ -27,6 +26,9 @@ import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
import static org.jackhuang.hmcl.util.gson.JsonUtils.mapTypeOf;
@JsonAdapter(MojangJavaDownloads.Adapter.class) @JsonAdapter(MojangJavaDownloads.Adapter.class)
public class MojangJavaDownloads { public class MojangJavaDownloads {
@@ -49,8 +51,7 @@ public class MojangJavaDownloads {
@Override @Override
public MojangJavaDownloads deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { public MojangJavaDownloads deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return new MojangJavaDownloads(context.deserialize(json, new TypeToken<Map<String, Map<String, List<JavaDownload>>>>() { return new MojangJavaDownloads(context.deserialize(json, mapTypeOf(String.class, mapTypeOf(String.class, listTypeOf(JavaDownload.class))).getType()));
}.getType()));
} }
} }

View File

@@ -19,18 +19,17 @@ package org.jackhuang.hmcl.download.neoforge;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.VersionList; import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.Immutable;
import org.jackhuang.hmcl.util.gson.Validation; import org.jackhuang.hmcl.util.gson.Validation;
import org.jackhuang.hmcl.util.io.HttpRequest; import org.jackhuang.hmcl.util.io.HttpRequest;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import static org.jackhuang.hmcl.util.Lang.wrap; import static org.jackhuang.hmcl.util.Lang.wrap;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
public final class NeoForgeBMCLVersionList extends VersionList<NeoForgeRemoteVersion> { public final class NeoForgeBMCLVersionList extends VersionList<NeoForgeRemoteVersion> {
private final String apiRoot; private final String apiRoot;
@@ -68,8 +67,7 @@ public final class NeoForgeBMCLVersionList extends VersionList<NeoForgeRemoteVer
@Override @Override
public CompletableFuture<?> refreshAsync(String gameVersion) { public CompletableFuture<?> refreshAsync(String gameVersion) {
return CompletableFuture.completedFuture((Void) null) return CompletableFuture.completedFuture((Void) null)
.thenApplyAsync(wrap(unused -> HttpRequest.GET(apiRoot + "/neoforge/list/" + gameVersion).<List<NeoForgeVersion>>getJson(new TypeToken<List<NeoForgeVersion>>() { .thenApplyAsync(wrap(unused -> HttpRequest.GET(apiRoot + "/neoforge/list/" + gameVersion).getJson(listTypeOf(NeoForgeVersion.class))))
}.getType())))
.thenAcceptAsync(neoForgeVersions -> { .thenAcceptAsync(neoForgeVersions -> {
lock.writeLock().lock(); lock.writeLock().lock();

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.download.optifine; package org.jackhuang.hmcl.download.optifine;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.VersionList; import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.HttpRequest; import org.jackhuang.hmcl.util.io.HttpRequest;
@@ -26,10 +25,11 @@ import org.jackhuang.hmcl.util.versioning.VersionNumber;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
/** /**
* @author huangyuhui * @author huangyuhui
*/ */
@@ -72,8 +72,7 @@ public final class OptiFineBMCLVersionList extends VersionList<OptiFineRemoteVer
@Override @Override
public CompletableFuture<?> refreshAsync() { public CompletableFuture<?> refreshAsync() {
return HttpRequest.GET(apiRoot + "/optifine/versionlist").<List<OptiFineVersion>>getJsonAsync(new TypeToken<List<OptiFineVersion>>() { return HttpRequest.GET(apiRoot + "/optifine/versionlist").getJsonAsync(listTypeOf(OptiFineVersion.class)).thenAcceptAsync(root -> {
}.getType()).thenAcceptAsync(root -> {
lock.writeLock().lock(); lock.writeLock().lock();
try { try {

View File

@@ -17,7 +17,6 @@
*/ */
package org.jackhuang.hmcl.download.quilt; package org.jackhuang.hmcl.download.quilt;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.download.VersionList; import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
@@ -25,13 +24,13 @@ import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.Lang.wrap; import static org.jackhuang.hmcl.util.Lang.wrap;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
public final class QuiltVersionList extends VersionList<QuiltRemoteVersion> { public final class QuiltVersionList extends VersionList<QuiltRemoteVersion> {
private final DownloadProvider downloadProvider; private final DownloadProvider downloadProvider;
@@ -69,8 +68,8 @@ public final class QuiltVersionList extends VersionList<QuiltRemoteVersion> {
private List<String> getGameVersions(String metaUrl) throws IOException { private List<String> getGameVersions(String metaUrl) throws IOException {
String json = NetworkUtils.doGet(downloadProvider.injectURLWithCandidates(metaUrl)); String json = NetworkUtils.doGet(downloadProvider.injectURLWithCandidates(metaUrl));
return JsonUtils.GSON.<ArrayList<GameVersion>>fromJson(json, new TypeToken<ArrayList<GameVersion>>() { return JsonUtils.GSON.fromJson(json, listTypeOf(GameVersion.class))
}.getType()).stream().map(GameVersion::getVersion).collect(Collectors.toList()); .stream().map(GameVersion::getVersion).collect(Collectors.toList());
} }
private static String getLaunchMetaUrl(String gameVersion, String loaderVersion) { private static String getLaunchMetaUrl(String gameVersion, String loaderVersion) {

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.game; package org.jackhuang.hmcl.game;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.MaintainTask; import org.jackhuang.hmcl.download.MaintainTask;
import org.jackhuang.hmcl.download.game.VersionJsonSaveTask; import org.jackhuang.hmcl.download.game.VersionJsonSaveTask;
import org.jackhuang.hmcl.event.*; import org.jackhuang.hmcl.event.*;
@@ -499,18 +498,16 @@ public class DefaultGameRepository implements GameRepository {
* read modpack configuration for a version. * read modpack configuration for a version.
* *
* @param version version installed as modpack * @param version version installed as modpack
* @param <M> manifest type of ModpackConfiguration
* @return modpack configuration object, or null if this version is not a modpack. * @return modpack configuration object, or null if this version is not a modpack.
* @throws VersionNotFoundException if version does not exist. * @throws VersionNotFoundException if version does not exist.
* @throws IOException if an i/o error occurs. * @throws IOException if an i/o error occurs.
*/ */
@Nullable @Nullable
public <M> ModpackConfiguration<M> readModpackConfiguration(String version) throws IOException, VersionNotFoundException { public ModpackConfiguration<?> readModpackConfiguration(String version) throws IOException, VersionNotFoundException {
if (!hasVersion(version)) throw new VersionNotFoundException(version); if (!hasVersion(version)) throw new VersionNotFoundException(version);
File file = getModpackConfiguration(version); File file = getModpackConfiguration(version);
if (!file.exists()) return null; if (!file.exists()) return null;
return JsonUtils.GSON.fromJson(FileUtils.readText(file), new TypeToken<ModpackConfiguration<M>>() { return JsonUtils.GSON.fromJson(FileUtils.readText(file), ModpackConfiguration.class);
}.getType());
} }
public boolean isModpack(String version) { public boolean isModpack(String version) {

View File

@@ -19,13 +19,14 @@ package org.jackhuang.hmcl.game;
import com.google.gson.*; import com.google.gson.*;
import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.JsonAdapter;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.Immutable;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
/** /**
* *
* @author huangyuhui * @author huangyuhui
@@ -86,8 +87,7 @@ public class RuledArgument implements Argument {
public RuledArgument deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { public RuledArgument deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject obj = json.getAsJsonObject(); JsonObject obj = json.getAsJsonObject();
List<CompatibilityRule> rules = context.deserialize(obj.get("rules"), new TypeToken<List<CompatibilityRule>>() { List<CompatibilityRule> rules = context.deserialize(obj.get("rules"), listTypeOf(CompatibilityRule.class).getType());
}.getType());
JsonElement valuesElement; JsonElement valuesElement;
if (obj.has("values")) { if (obj.has("values")) {
@@ -102,8 +102,7 @@ public class RuledArgument implements Argument {
if (valuesElement.isJsonPrimitive()) { if (valuesElement.isJsonPrimitive()) {
values = Collections.singletonList(valuesElement.getAsString()); values = Collections.singletonList(valuesElement.getAsString());
} else { } else {
values = context.deserialize(valuesElement, new TypeToken<List<String>>() { values = context.deserialize(valuesElement, listTypeOf(String.class).getType());
}.getType());
} }
return new RuledArgument(rules, values); return new RuledArgument(rules, values);

View File

@@ -18,6 +18,7 @@
package org.jackhuang.hmcl.mod; package org.jackhuang.hmcl.mod;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.Immutable;
import org.jackhuang.hmcl.util.gson.Validation; import org.jackhuang.hmcl.util.gson.Validation;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -29,6 +30,11 @@ import java.util.List;
@Immutable @Immutable
public final class ModpackConfiguration<T> implements Validation { public final class ModpackConfiguration<T> implements Validation {
@SuppressWarnings("unchecked")
public static <T> TypeToken<ModpackConfiguration<T>> typeOf(Class<T> clazz) {
return (TypeToken<ModpackConfiguration<T>>) TypeToken.getParameterized(ModpackConfiguration.class, clazz);
}
private final T manifest; private final T manifest;
private final String type; private final String type;
private final String name; private final String name;

View File

@@ -38,6 +38,7 @@ import java.util.stream.Stream;
import static org.jackhuang.hmcl.util.Lang.mapOf; import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
public final class CurseForgeRemoteModRepository implements RemoteModRepository { public final class CurseForgeRemoteModRepository implements RemoteModRepository {
@@ -113,8 +114,7 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
pair("index", Integer.toString(pageOffset * pageSize)), pair("index", Integer.toString(pageOffset * pageSize)),
pair("pageSize", Integer.toString(pageSize))) pair("pageSize", Integer.toString(pageSize)))
.header("X-API-KEY", apiKey) .header("X-API-KEY", apiKey)
.getJson(new TypeToken<Response<List<CurseAddon>>>() { .getJson(Response.typeOf(listTypeOf(CurseAddon.class)));
}.getType());
if (searchFilter.isEmpty()) { if (searchFilter.isEmpty()) {
return new SearchResult(response.getData().stream().map(CurseAddon::toMod), calculateTotalPages(response, pageSize)); return new SearchResult(response.getData().stream().map(CurseAddon::toMod), calculateTotalPages(response, pageSize));
} }
@@ -163,8 +163,7 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
Response<FingerprintMatchesResult> response = HttpRequest.POST(PREFIX + "/v1/fingerprints/432") Response<FingerprintMatchesResult> response = HttpRequest.POST(PREFIX + "/v1/fingerprints/432")
.json(mapOf(pair("fingerprints", Collections.singletonList(hash)))) .json(mapOf(pair("fingerprints", Collections.singletonList(hash))))
.header("X-API-KEY", apiKey) .header("X-API-KEY", apiKey)
.getJson(new TypeToken<Response<FingerprintMatchesResult>>() { .getJson(Response.typeOf(FingerprintMatchesResult.class));
}.getType());
if (response.getData().getExactMatches() == null || response.getData().getExactMatches().isEmpty()) { if (response.getData().getExactMatches() == null || response.getData().getExactMatches().isEmpty()) {
return Optional.empty(); return Optional.empty();
@@ -177,8 +176,7 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
public RemoteMod getModById(String id) throws IOException { public RemoteMod getModById(String id) throws IOException {
Response<CurseAddon> response = HttpRequest.GET(PREFIX + "/v1/mods/" + id) Response<CurseAddon> response = HttpRequest.GET(PREFIX + "/v1/mods/" + id)
.header("X-API-KEY", apiKey) .header("X-API-KEY", apiKey)
.getJson(new TypeToken<Response<CurseAddon>>() { .getJson(Response.typeOf(CurseAddon.class));
}.getType());
return response.data.toMod(); return response.data.toMod();
} }
@@ -186,8 +184,7 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
public RemoteMod.File getModFile(String modId, String fileId) throws IOException { public RemoteMod.File getModFile(String modId, String fileId) throws IOException {
Response<CurseAddon.LatestFile> response = HttpRequest.GET(String.format("%s/v1/mods/%s/files/%s", PREFIX, modId, fileId)) Response<CurseAddon.LatestFile> response = HttpRequest.GET(String.format("%s/v1/mods/%s/files/%s", PREFIX, modId, fileId))
.header("X-API-KEY", apiKey) .header("X-API-KEY", apiKey)
.getJson(new TypeToken<Response<CurseAddon.LatestFile>>() { .getJson(Response.typeOf(CurseAddon.LatestFile.class));
}.getType());
return response.getData().toVersion().getFile(); return response.getData().toVersion().getFile();
} }
@@ -196,16 +193,14 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
Response<List<CurseAddon.LatestFile>> response = HttpRequest.GET(PREFIX + "/v1/mods/" + id + "/files", Response<List<CurseAddon.LatestFile>> response = HttpRequest.GET(PREFIX + "/v1/mods/" + id + "/files",
pair("pageSize", "10000")) pair("pageSize", "10000"))
.header("X-API-KEY", apiKey) .header("X-API-KEY", apiKey)
.getJson(new TypeToken<Response<List<CurseAddon.LatestFile>>>() { .getJson(Response.typeOf(listTypeOf(CurseAddon.LatestFile.class)));
}.getType());
return response.getData().stream().map(CurseAddon.LatestFile::toVersion); return response.getData().stream().map(CurseAddon.LatestFile::toVersion);
} }
public List<CurseAddon.Category> getCategoriesImpl() throws IOException { public List<CurseAddon.Category> getCategoriesImpl() throws IOException {
Response<List<CurseAddon.Category>> categories = HttpRequest.GET(PREFIX + "/v1/categories", pair("gameId", "432")) Response<List<CurseAddon.Category>> categories = HttpRequest.GET(PREFIX + "/v1/categories", pair("gameId", "432"))
.header("X-API-KEY", apiKey) .header("X-API-KEY", apiKey)
.getJson(new TypeToken<Response<List<CurseAddon.Category>>>() { .getJson(Response.typeOf(listTypeOf(CurseAddon.Category.class)));
}.getType());
return reorganizeCategories(categories.getData(), section); return reorganizeCategories(categories.getData(), section);
} }
@@ -284,6 +279,17 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
} }
public static class Response<T> { public static class Response<T> {
@SuppressWarnings("unchecked")
public static <T> TypeToken<Response<T>> typeOf(Class<T> responseType) {
return (TypeToken<Response<T>>) TypeToken.getParameterized(Response.class, responseType);
}
@SuppressWarnings("unchecked")
public static <T> TypeToken<Response<T>> typeOf(TypeToken<T> responseType) {
return (TypeToken<Response<T>>) TypeToken.getParameterized(Response.class, responseType.getType());
}
private final T data; private final T data;
private final Pagination pagination; private final Pagination pagination;

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.mod.curse; package org.jackhuang.hmcl.mod.curse;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.GameBuilder;
import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.DefaultGameRepository;
@@ -99,8 +98,7 @@ public final class CurseInstallTask extends Task<Void> {
ModpackConfiguration<CurseManifest> config = null; ModpackConfiguration<CurseManifest> config = null;
try { try {
if (json.exists()) { if (json.exists()) {
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<CurseManifest>>() { config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(CurseManifest.class));
}.getType());
if (!CurseModpackProvider.INSTANCE.getName().equals(config.getType())) if (!CurseModpackProvider.INSTANCE.getName().equals(config.getType()))
throw new IllegalArgumentException("Version " + name + " is not a Curse modpack. Cannot update this version."); throw new IllegalArgumentException("Version " + name + " is not a Curse modpack. Cannot update this version.");

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.mod.mcbbs; package org.jackhuang.hmcl.mod.mcbbs;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.DefaultGameRepository;
import org.jackhuang.hmcl.mod.ModManager; import org.jackhuang.hmcl.mod.ModManager;
@@ -88,8 +87,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask<Void> {
if (configuration == null) { if (configuration == null) {
// Load configuration from disk // Load configuration from disk
try { try {
configuration = JsonUtils.fromNonNullJson(FileUtils.readText(configurationFile), new TypeToken<ModpackConfiguration<McbbsModpackManifest>>() { configuration = JsonUtils.fromNonNullJson(FileUtils.readText(configurationFile), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
}.getType());
} catch (IOException | JsonParseException e) { } catch (IOException | JsonParseException e) {
throw new IOException("Malformed modpack configuration"); throw new IOException("Malformed modpack configuration");
} }

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.mod.mcbbs; package org.jackhuang.hmcl.mod.mcbbs;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.GameBuilder;
import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.DefaultGameRepository;
@@ -80,8 +79,7 @@ public class McbbsModpackLocalInstallTask extends Task<Void> {
ModpackConfiguration<McbbsModpackManifest> config = null; ModpackConfiguration<McbbsModpackManifest> config = null;
try { try {
if (json.exists()) { if (json.exists()) {
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<McbbsModpackManifest>>() { config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
}.getType());
if (!McbbsModpackProvider.INSTANCE.getName().equals(config.getType())) if (!McbbsModpackProvider.INSTANCE.getName().equals(config.getType()))
throw new IllegalArgumentException("Version " + name + " is not a Mcbbs modpack. Cannot update this version."); throw new IllegalArgumentException("Version " + name + " is not a Mcbbs modpack. Cannot update this version.");

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.mod.mcbbs; package org.jackhuang.hmcl.mod.mcbbs;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile; import org.apache.commons.compress.archivers.zip.ZipFile;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
@@ -56,8 +55,7 @@ public final class McbbsModpackProvider implements ModpackProvider {
@Override @Override
public void injectLaunchOptions(String modpackConfigurationJson, LaunchOptions.Builder builder) { public void injectLaunchOptions(String modpackConfigurationJson, LaunchOptions.Builder builder) {
ModpackConfiguration<McbbsModpackManifest> config = JsonUtils.GSON.fromJson(modpackConfigurationJson, new TypeToken<ModpackConfiguration<McbbsModpackManifest>>() { ModpackConfiguration<McbbsModpackManifest> config = JsonUtils.GSON.fromJson(modpackConfigurationJson, ModpackConfiguration.typeOf(McbbsModpackManifest.class));
}.getType());
if (!getName().equals(config.getType())) { if (!getName().equals(config.getType())) {
throw new IllegalArgumentException("Incorrect manifest type, actual=" + config.getType() + ", expected=" + getName()); throw new IllegalArgumentException("Incorrect manifest type, actual=" + config.getType() + ", expected=" + getName());

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.mod.mcbbs; package org.jackhuang.hmcl.mod.mcbbs;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.GameBuilder;
import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.DefaultGameRepository;
@@ -66,8 +65,7 @@ public class McbbsModpackRemoteInstallTask extends Task<Void> {
ModpackConfiguration<McbbsModpackManifest> config = null; ModpackConfiguration<McbbsModpackManifest> config = null;
try { try {
if (json.exists()) { if (json.exists()) {
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<McbbsModpackManifest>>() { config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
}.getType());
if (!MODPACK_TYPE.equals(config.getType())) if (!MODPACK_TYPE.equals(config.getType()))
throw new IllegalArgumentException("Version " + name + " is not a Mcbbs modpack. Cannot update this version."); throw new IllegalArgumentException("Version " + name + " is not a Mcbbs modpack. Cannot update this version.");

View File

@@ -19,7 +19,6 @@ package org.jackhuang.hmcl.mod.modinfo;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.mod.LocalModFile; import org.jackhuang.hmcl.mod.LocalModFile;
import org.jackhuang.hmcl.mod.ModLoaderType; import org.jackhuang.hmcl.mod.ModLoaderType;
import org.jackhuang.hmcl.mod.ModManager; import org.jackhuang.hmcl.mod.ModManager;
@@ -34,6 +33,8 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
/** /**
* *
* @author huangyuhui * @author huangyuhui
@@ -125,9 +126,7 @@ public final class ForgeOldModMetadata {
Path mcmod = fs.getPath("mcmod.info"); Path mcmod = fs.getPath("mcmod.info");
if (Files.notExists(mcmod)) if (Files.notExists(mcmod))
throw new IOException("File " + modFile + " is not a Forge mod."); throw new IOException("File " + modFile + " is not a Forge mod.");
List<ForgeOldModMetadata> modList = JsonUtils.GSON.fromJson(FileUtils.readText(mcmod), List<ForgeOldModMetadata> modList = JsonUtils.GSON.fromJson(FileUtils.readText(mcmod), listTypeOf(ForgeOldModMetadata.class));
new TypeToken<List<ForgeOldModMetadata>>() {
}.getType());
if (modList == null || modList.isEmpty()) if (modList == null || modList.isEmpty())
throw new IOException("Mod " + modFile + " `mcmod.info` is malformed.."); throw new IOException("Mod " + modFile + " `mcmod.info` is malformed..");
ForgeOldModMetadata metadata = modList.get(0); ForgeOldModMetadata metadata = modList.get(0);

View File

@@ -18,12 +18,10 @@
package org.jackhuang.hmcl.mod.modrinth; package org.jackhuang.hmcl.mod.modrinth;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.GameBuilder;
import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.DefaultGameRepository;
import org.jackhuang.hmcl.mod.*; import org.jackhuang.hmcl.mod.*;
import org.jackhuang.hmcl.mod.curse.CurseManifest;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
@@ -95,8 +93,7 @@ public class ModrinthInstallTask extends Task<Void> {
ModpackConfiguration<ModrinthManifest> config = null; ModpackConfiguration<ModrinthManifest> config = null;
try { try {
if (json.exists()) { if (json.exists()) {
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<CurseManifest>>() { config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(ModrinthManifest.class));
}.getType());
if (!ModrinthModpackProvider.INSTANCE.getName().equals(config.getType())) if (!ModrinthModpackProvider.INSTANCE.getName().equals(config.getType()))
throw new IllegalArgumentException("Version " + name + " is not a Modrinth modpack. Cannot update this version."); throw new IllegalArgumentException("Version " + name + " is not a Modrinth modpack. Cannot update this version.");

View File

@@ -39,6 +39,7 @@ import java.util.stream.Stream;
import static org.jackhuang.hmcl.util.Lang.mapOf; import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
public final class ModrinthRemoteModRepository implements RemoteModRepository { public final class ModrinthRemoteModRepository implements RemoteModRepository {
public static final ModrinthRemoteModRepository MODS = new ModrinthRemoteModRepository("mod"); public static final ModrinthRemoteModRepository MODS = new ModrinthRemoteModRepository("mod");
@@ -93,8 +94,7 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
pair("index", convertSortType(sort)) pair("index", convertSortType(sort))
); );
Response<ProjectSearchResult> response = HttpRequest.GET(NetworkUtils.withQuery(PREFIX + "/v2/search", query)) Response<ProjectSearchResult> response = HttpRequest.GET(NetworkUtils.withQuery(PREFIX + "/v2/search", query))
.getJson(new TypeToken<Response<ProjectSearchResult>>() { .getJson(Response.typeOf(ProjectSearchResult.class));
}.getType());
return new SearchResult(response.getHits().stream().map(ProjectSearchResult::toMod), (int) Math.ceil((double) response.totalHits / pageSize)); return new SearchResult(response.getHits().stream().map(ProjectSearchResult::toMod), (int) Math.ceil((double) response.totalHits / pageSize));
} }
@@ -132,13 +132,12 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
public Stream<RemoteMod.Version> getRemoteVersionsById(String id) throws IOException { public Stream<RemoteMod.Version> getRemoteVersionsById(String id) throws IOException {
id = StringUtils.removePrefix(id, "local-"); id = StringUtils.removePrefix(id, "local-");
List<ProjectVersion> versions = HttpRequest.GET(PREFIX + "/v2/project/" + id + "/version") List<ProjectVersion> versions = HttpRequest.GET(PREFIX + "/v2/project/" + id + "/version")
.getJson(new TypeToken<List<ProjectVersion>>() { .getJson(listTypeOf(ProjectVersion.class));
}.getType());
return versions.stream().map(ProjectVersion::toVersion).flatMap(Lang::toStream); return versions.stream().map(ProjectVersion::toVersion).flatMap(Lang::toStream);
} }
public List<Category> getCategoriesImpl() throws IOException { public List<Category> getCategoriesImpl() throws IOException {
List<Category> categories = HttpRequest.GET(PREFIX + "/v2/tag/category").getJson(new TypeToken<List<Category>>() {}.getType()); List<Category> categories = HttpRequest.GET(PREFIX + "/v2/tag/category").getJson(listTypeOf(Category.class));
return categories.stream().filter(category -> category.getProjectType().equals(projectType)).collect(Collectors.toList()); return categories.stream().filter(category -> category.getProjectType().equals(projectType)).collect(Collectors.toList());
} }
@@ -696,6 +695,12 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
} }
public static class Response<T> { public static class Response<T> {
@SuppressWarnings("unchecked")
public static <T> TypeToken<Response<T>> typeOf(Class<T> responseType) {
return (TypeToken<Response<T>>) TypeToken.getParameterized(Response.class, responseType);
}
private final int offset; private final int offset;
private final int limit; private final int limit;

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.mod.multimc; package org.jackhuang.hmcl.mod.multimc;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.GameBuilder;
import org.jackhuang.hmcl.game.Arguments; import org.jackhuang.hmcl.game.Arguments;
@@ -128,8 +127,7 @@ public final class MultiMCModpackInstallTask extends Task<Void> {
ModpackConfiguration<MultiMCInstanceConfiguration> config = null; ModpackConfiguration<MultiMCInstanceConfiguration> config = null;
try { try {
if (json.exists()) { if (json.exists()) {
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<MultiMCInstanceConfiguration>>() { config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(MultiMCInstanceConfiguration.class));
}.getType());
if (!MultiMCModpackProvider.INSTANCE.getName().equals(config.getType())) if (!MultiMCModpackProvider.INSTANCE.getName().equals(config.getType()))
throw new IllegalArgumentException("Version " + name + " is not a MultiMC modpack. Cannot update this version."); throw new IllegalArgumentException("Version " + name + " is not a MultiMC modpack. Cannot update this version.");

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.mod.server; package org.jackhuang.hmcl.mod.server;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.GameBuilder;
import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.DefaultGameRepository;
@@ -66,8 +65,7 @@ public class ServerModpackCompletionTask extends Task<Void> {
try { try {
File manifestFile = repository.getModpackConfiguration(version); File manifestFile = repository.getModpackConfiguration(version);
if (manifestFile.exists()) { if (manifestFile.exists()) {
this.manifest = JsonUtils.GSON.fromJson(FileUtils.readText(manifestFile), new TypeToken<ModpackConfiguration<ServerModpackManifest>>() { this.manifest = JsonUtils.GSON.fromJson(FileUtils.readText(manifestFile), ModpackConfiguration.typeOf(ServerModpackManifest.class));
}.getType());
} }
} catch (Exception e) { } catch (Exception e) {
LOG.warning("Unable to read Server modpack manifest.json", e); LOG.warning("Unable to read Server modpack manifest.json", e);

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.mod.server; package org.jackhuang.hmcl.mod.server;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.GameBuilder;
import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.DefaultGameRepository;
@@ -72,8 +71,7 @@ public class ServerModpackLocalInstallTask extends Task<Void> {
ModpackConfiguration<ServerModpackManifest> config = null; ModpackConfiguration<ServerModpackManifest> config = null;
try { try {
if (json.exists()) { if (json.exists()) {
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<ServerModpackManifest>>() { config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(ServerModpackManifest.class));
}.getType());
if (!ServerModpackProvider.INSTANCE.getName().equals(config.getType())) if (!ServerModpackProvider.INSTANCE.getName().equals(config.getType()))
throw new IllegalArgumentException("Version " + name + " is not a Server modpack. Cannot update this version."); throw new IllegalArgumentException("Version " + name + " is not a Server modpack. Cannot update this version.");

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.mod.server; package org.jackhuang.hmcl.mod.server;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.GameBuilder;
import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.DefaultGameRepository;
@@ -63,11 +62,10 @@ public class ServerModpackRemoteInstallTask extends Task<Void> {
repository.removeVersionFromDisk(name); repository.removeVersionFromDisk(name);
}); });
ModpackConfiguration<ServerModpackManifest> config = null; ModpackConfiguration<ServerModpackManifest> config;
try { try {
if (json.exists()) { if (json.exists()) {
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<ServerModpackManifest>>() { config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(ServerModpackManifest.class));
}.getType());
if (!MODPACK_TYPE.equals(config.getType())) if (!MODPACK_TYPE.equals(config.getType()))
throw new IllegalArgumentException("Version " + name + " is not a Server modpack. Cannot update this version."); throw new IllegalArgumentException("Version " + name + " is not a Server modpack. Cannot update this version.");

View File

@@ -19,9 +19,7 @@ package org.jackhuang.hmcl.util;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.util.function.ExceptionalSupplier; import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.IOUtils; import org.jackhuang.hmcl.util.io.IOUtils;
@@ -46,6 +44,7 @@ import java.util.function.BiFunction;
import java.util.stream.Stream; import java.util.stream.Stream;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import static org.jackhuang.hmcl.util.gson.JsonUtils.*;
import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class CacheRepository { public class CacheRepository {
@@ -68,7 +67,7 @@ public class CacheRepository {
} }
if (Files.isRegularFile(indexFile)) { if (Files.isRegularFile(indexFile)) {
ETagIndex raw = JsonUtils.GSON.fromJson(FileUtils.readText(indexFile), ETagIndex.class); ETagIndex raw = GSON.fromJson(FileUtils.readText(indexFile), ETagIndex.class);
if (raw == null) if (raw == null)
index = new HashMap<>(); index = new HashMap<>();
else else
@@ -289,10 +288,10 @@ public class CacheRepository {
try (FileChannel channel = FileChannel.open(indexFile, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)) { try (FileChannel channel = FileChannel.open(indexFile, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
FileLock lock = channel.lock(); FileLock lock = channel.lock();
try { try {
ETagIndex indexOnDisk = JsonUtils.fromMaybeMalformedJson(new String(IOUtils.readFullyWithoutClosing(Channels.newInputStream(channel)), UTF_8), ETagIndex.class); ETagIndex indexOnDisk = fromMaybeMalformedJson(new String(IOUtils.readFullyWithoutClosing(Channels.newInputStream(channel)), UTF_8), ETagIndex.class);
Map<String, ETagItem> newIndex = joinETagIndexes(indexOnDisk == null ? null : indexOnDisk.eTag, index.values()); Map<String, ETagItem> newIndex = joinETagIndexes(indexOnDisk == null ? null : indexOnDisk.eTag, index.values());
channel.truncate(0); channel.truncate(0);
ByteBuffer writeTo = ByteBuffer.wrap(JsonUtils.GSON.toJson(new ETagIndex(newIndex.values())).getBytes(UTF_8)); ByteBuffer writeTo = ByteBuffer.wrap(GSON.toJson(new ETagIndex(newIndex.values())).getBytes(UTF_8));
while (writeTo.hasRemaining()) { while (writeTo.hasRemaining()) {
if (channel.write(writeTo) == 0) { if (channel.write(writeTo) == 0) {
throw new IOException("No value is written"); throw new IOException("No value is written");
@@ -412,8 +411,7 @@ public class CacheRepository {
try { try {
indexFile = cacheDirectory.resolve(name + ".json"); indexFile = cacheDirectory.resolve(name + ".json");
if (Files.isRegularFile(indexFile)) { if (Files.isRegularFile(indexFile)) {
joinEntries(JsonUtils.fromNonNullJson(FileUtils.readText(indexFile), new TypeToken<Map<String, Object>>() { joinEntries(fromNonNullJson(FileUtils.readText(indexFile), mapTypeOf(String.class, Object.class)));
}.getType()));
} }
} catch (IOException | JsonParseException e) { } catch (IOException | JsonParseException e) {
LOG.warning("Unable to read storage {" + name + "} file"); LOG.warning("Unable to read storage {" + name + "} file");
@@ -426,12 +424,11 @@ public class CacheRepository {
try (FileChannel channel = FileChannel.open(indexFile, StandardOpenOption.READ, StandardOpenOption.WRITE)) { try (FileChannel channel = FileChannel.open(indexFile, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
FileLock lock = channel.lock(); FileLock lock = channel.lock();
try { try {
Map<String, Object> indexOnDisk = JsonUtils.fromMaybeMalformedJson(new String(IOUtils.readFullyWithoutClosing(Channels.newInputStream(channel)), UTF_8), new TypeToken<Map<String, Object>>() { Map<String, Object> indexOnDisk = fromMaybeMalformedJson(new String(IOUtils.readFullyWithoutClosing(Channels.newInputStream(channel)), UTF_8), mapTypeOf(String.class, Object.class));
}.getType());
if (indexOnDisk == null) indexOnDisk = new HashMap<>(); if (indexOnDisk == null) indexOnDisk = new HashMap<>();
indexOnDisk.putAll(storage); indexOnDisk.putAll(storage);
channel.truncate(0); channel.truncate(0);
channel.write(ByteBuffer.wrap(JsonUtils.GSON.toJson(storage).getBytes(UTF_8))); channel.write(ByteBuffer.wrap(GSON.toJson(storage).getBytes(UTF_8)));
this.storage = indexOnDisk; this.storage = indexOnDisk;
} finally { } finally {
lock.release(); lock.release();

View File

@@ -27,14 +27,16 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Instant; import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
/** /**
* @author yushijinhun * @author yushijinhun
*/ */
@SuppressWarnings("unchecked")
public final class JsonUtils { public final class JsonUtils {
public static final Gson GSON = defaultGsonBuilder().create(); public static final Gson GSON = defaultGsonBuilder().create();
@@ -48,13 +50,29 @@ public final class JsonUtils {
private JsonUtils() { private JsonUtils() {
} }
public static <T> TypeToken<List<T>> listTypeOf(Class<T> elementType) {
return (TypeToken<List<T>>) TypeToken.getParameterized(List.class, elementType);
}
public static <T> TypeToken<List<T>> listTypeOf(TypeToken<T> elementType) {
return (TypeToken<List<T>>) TypeToken.getParameterized(List.class, elementType.getType());
}
public static <K, V> TypeToken<Map<K, V>> mapTypeOf(Class<K> keyType, Class<V> valueType) {
return (TypeToken<Map<K, V>>) TypeToken.getParameterized(Map.class, keyType, valueType);
}
public static <K, V> TypeToken<Map<K, V>> mapTypeOf(Class<K> keyType, TypeToken<V> valueType) {
return (TypeToken<Map<K, V>>) TypeToken.getParameterized(Map.class, keyType, valueType.getType());
}
public static <T> T fromJsonFully(InputStream json, Class<T> classOfT) throws IOException, JsonParseException { public static <T> T fromJsonFully(InputStream json, Class<T> classOfT) throws IOException, JsonParseException {
try (InputStreamReader reader = new InputStreamReader(json, StandardCharsets.UTF_8)) { try (InputStreamReader reader = new InputStreamReader(json, StandardCharsets.UTF_8)) {
return GSON.fromJson(reader, classOfT); return GSON.fromJson(reader, classOfT);
} }
} }
public static <T> T fromJsonFully(InputStream json, Type type) throws IOException, JsonParseException { public static <T> T fromJsonFully(InputStream json, TypeToken<T> type) throws IOException, JsonParseException {
try (InputStreamReader reader = new InputStreamReader(json, StandardCharsets.UTF_8)) { try (InputStreamReader reader = new InputStreamReader(json, StandardCharsets.UTF_8)) {
return GSON.fromJson(reader, type); return GSON.fromJson(reader, type);
} }
@@ -67,13 +85,6 @@ public final class JsonUtils {
return parsed; return parsed;
} }
public static <T> T fromNonNullJson(String json, Type type) throws JsonParseException {
T parsed = GSON.fromJson(json, type);
if (parsed == null)
throw new JsonParseException("Json object cannot be null.");
return parsed;
}
public static <T> T fromNonNullJson(String json, TypeToken<T> type) throws JsonParseException { public static <T> T fromNonNullJson(String json, TypeToken<T> type) throws JsonParseException {
T parsed = GSON.fromJson(json, type); T parsed = GSON.fromJson(json, type);
if (parsed == null) if (parsed == null)
@@ -90,7 +101,7 @@ public final class JsonUtils {
} }
} }
public static <T> T fromNonNullJsonFully(InputStream json, Type type) throws IOException, JsonParseException { public static <T> T fromNonNullJsonFully(InputStream json, TypeToken<T> type) throws IOException, JsonParseException {
try (InputStreamReader reader = new InputStreamReader(json, StandardCharsets.UTF_8)) { try (InputStreamReader reader = new InputStreamReader(json, StandardCharsets.UTF_8)) {
T parsed = GSON.fromJson(reader, type); T parsed = GSON.fromJson(reader, type);
if (parsed == null) if (parsed == null)
@@ -107,7 +118,7 @@ public final class JsonUtils {
} }
} }
public static <T> T fromMaybeMalformedJson(String json, Type type) throws JsonParseException { public static <T> T fromMaybeMalformedJson(String json, TypeToken<T> type) throws JsonParseException {
try { try {
return GSON.fromJson(json, type); return GSON.fromJson(json, type);
} catch (JsonSyntaxException e) { } catch (JsonSyntaxException e) {

View File

@@ -18,6 +18,7 @@
package org.jackhuang.hmcl.util.io; package org.jackhuang.hmcl.util.io;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.util.Pair; import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.function.ExceptionalBiConsumer; import org.jackhuang.hmcl.util.function.ExceptionalBiConsumer;
@@ -26,7 +27,6 @@ import org.jackhuang.hmcl.util.gson.JsonUtils;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Type;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
@@ -101,7 +101,7 @@ public abstract class HttpRequest {
return JsonUtils.fromNonNullJson(getString(), typeOfT); return JsonUtils.fromNonNullJson(getString(), typeOfT);
} }
public <T> T getJson(Type type) throws IOException, JsonParseException { public <T> T getJson(TypeToken<T> type) throws IOException, JsonParseException {
return JsonUtils.fromNonNullJson(getString(), type); return JsonUtils.fromNonNullJson(getString(), type);
} }
@@ -109,7 +109,7 @@ public abstract class HttpRequest {
return getStringAsync().thenApplyAsync(jsonString -> JsonUtils.fromNonNullJson(jsonString, typeOfT)); return getStringAsync().thenApplyAsync(jsonString -> JsonUtils.fromNonNullJson(jsonString, typeOfT));
} }
public <T> CompletableFuture<T> getJsonAsync(Type type) { public <T> CompletableFuture<T> getJsonAsync(TypeToken<T> type) {
return getStringAsync().thenApplyAsync(jsonString -> JsonUtils.fromNonNullJson(jsonString, type)); return getStringAsync().thenApplyAsync(jsonString -> JsonUtils.fromNonNullJson(jsonString, type));
} }

View File

@@ -0,0 +1,42 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2024 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.util.gson;
import com.google.gson.reflect.TypeToken;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
import static org.jackhuang.hmcl.util.gson.JsonUtils.mapTypeOf;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Glavo
*/
public class JsonUtilsTest {
@Test
public void testGetTypeToken() {
assertEquals(new TypeToken<List<Object>>(){}, listTypeOf(Object.class));
assertEquals(new TypeToken<List<String>>(){}, listTypeOf(String.class));
assertEquals(new TypeToken<List<Map<String, Integer>>>(){}, listTypeOf(mapTypeOf(String.class, Integer.class)));
assertEquals(new TypeToken<List<Map<String, List<Integer>>>>(){}, listTypeOf(mapTypeOf(String.class, listTypeOf(Integer.class))));
}
}