From d317844b28781624768538d54967fe62b08ba749 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 8 Jun 2025 09:45:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Java=20=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=97=A0=E6=B3=95=E6=B7=BB=E5=8A=A0=20IKVM?= =?UTF-8?q?=20=E7=9A=84=E9=97=AE=E9=A2=98=20(#3968)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HMCL/build.gradle.kts | 1 + .../hmcl/java/HMCLJavaRepository.java | 2 +- .../jackhuang/hmcl/java/JavaInfoUtils.java | 116 ++++++++++++++++++ .../org/jackhuang/hmcl/java/JavaManager.java | 11 +- .../org/jackhuang/hmcl/java/JavaInfo.java | 102 --------------- gradle/libs.versions.toml | 2 + 6 files changed, 124 insertions(+), 110 deletions(-) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/java/JavaInfoUtils.java diff --git a/HMCL/build.gradle.kts b/HMCL/build.gradle.kts index f9556b68d..750b00993 100644 --- a/HMCL/build.gradle.kts +++ b/HMCL/build.gradle.kts @@ -41,6 +41,7 @@ dependencies { implementation(project(":HMCLCore")) implementation("libs:JFoenix") implementation(libs.twelvemonkeys.imageio.webp) + implementation(libs.java.info) if (launcherExe == null) { implementation("org.glavo.hmcl:HMCLauncher:3.6.0.2") diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/java/HMCLJavaRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/java/HMCLJavaRepository.java index 473f8330e..2f6a3915d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/java/HMCLJavaRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/java/HMCLJavaRepository.java @@ -168,7 +168,7 @@ public final class HMCLJavaRepository implements JavaRepository { JavaInfo info; if (JavaManager.isCompatible(platform)) - info = JavaInfo.fromExecutable(executable, false); + info = JavaInfoUtils.fromExecutable(executable, false); else info = new JavaInfo(platform, result.download.getVersion().getName(), null); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaInfoUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaInfoUtils.java new file mode 100644 index 000000000..f67e4b163 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaInfoUtils.java @@ -0,0 +1,116 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui 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 . + */ +package org.jackhuang.hmcl.java; + +import com.google.gson.annotations.SerializedName; +import org.jackhuang.hmcl.util.gson.JsonUtils; +import org.jackhuang.hmcl.util.io.JarUtils; +import org.jackhuang.hmcl.util.platform.Architecture; +import org.jackhuang.hmcl.util.platform.OperatingSystem; +import org.jackhuang.hmcl.util.platform.Platform; +import org.jackhuang.hmcl.util.platform.SystemUtils; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * @author Glavo + * @see Glavo/java-info + */ +public final class JavaInfoUtils { + + private JavaInfoUtils() { + } + + private static Path tryFindReleaseFile(Path executable) { + Path parent = executable.getParent(); + if (parent != null && parent.getFileName() != null && parent.getFileName().toString().equals("bin")) { + Path javaHome = parent.getParent(); + if (javaHome != null && javaHome.getFileName() != null) { + Path releaseFile = javaHome.resolve("release"); + String javaHomeName = javaHome.getFileName().toString(); + if ((javaHomeName.contains("jre") || javaHomeName.contains("jdk") || javaHomeName.contains("openj9")) + && Files.isRegularFile(releaseFile)) { + return releaseFile; + } + } + } + return null; + } + + public static @NotNull JavaInfo fromExecutable(Path executable, boolean tryFindReleaseFile) throws IOException { + assert executable.isAbsolute(); + + Path releaseFile; + if (tryFindReleaseFile && (releaseFile = tryFindReleaseFile(executable)) != null) { + try { + return JavaInfo.fromReleaseFile(releaseFile); + } catch (IOException ignored) { + } + } + + Path thisPath = JarUtils.thisJarPath(); + + if (thisPath == null) { + throw new IOException("Failed to find current HMCL location"); + } + + try { + Result result = JsonUtils.GSON.fromJson(SystemUtils.run( + executable.toString(), + "-classpath", + thisPath.toString(), + org.glavo.info.Main.class.getName() + ), Result.class); + + if (result == null) { + throw new IOException("Failed to get Java info from " + executable); + } + + if (result.javaVersion == null) { + throw new IOException("Failed to get Java version from " + executable); + } + + Architecture architecture = Architecture.parseArchName(result.osArch); + Platform platform = Platform.getPlatform(OperatingSystem.CURRENT_OS, + architecture != Architecture.UNKNOWN + ? architecture + : Architecture.SYSTEM_ARCH); + + + return new JavaInfo(platform, result.javaVersion, result.javaVendor); + } catch (IOException e) { + throw e; + } catch (Throwable e) { + throw new IOException(e); + } + } + + private static final class Result { + @SerializedName("os.name") + public String osName; + @SerializedName("os.arch") + public String osArch; + @SerializedName("java.version") + public String javaVersion; + @SerializedName("java.vendor") + public String javaVendor; + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManager.java b/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManager.java index 553b4b051..3e2ccd0ac 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManager.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManager.java @@ -32,10 +32,7 @@ import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.util.CacheRepository; import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.io.FileUtils; -import org.jackhuang.hmcl.util.platform.Architecture; -import org.jackhuang.hmcl.util.platform.OperatingSystem; -import org.jackhuang.hmcl.util.platform.Platform; -import org.jackhuang.hmcl.util.platform.UnsupportedPlatformException; +import org.jackhuang.hmcl.util.platform.*; import org.jackhuang.hmcl.util.platform.windows.WinReg; import org.jackhuang.hmcl.util.versioning.GameVersionNumber; import org.jetbrains.annotations.Nullable; @@ -162,7 +159,7 @@ public final class JavaManager { return javaRuntime; } - JavaInfo info = JavaInfo.fromExecutable(executable); + JavaInfo info = JavaInfoUtils.fromExecutable(executable, true); return JavaRuntime.of(executable, info, false); } @@ -484,7 +481,7 @@ public final class JavaManager { info = JavaInfo.fromReleaseFile(releaseFile); } catch (IOException e) { try { - info = JavaInfo.fromExecutable(executable, false); + info = JavaInfoUtils.fromExecutable(executable, false); } catch (IOException e2) { e2.addSuppressed(e); LOG.warning("Failed to lookup Java executable at " + executable, e2); @@ -509,7 +506,7 @@ public final class JavaManager { JavaInfo info = null; try { - info = JavaInfo.fromExecutable(executable); + info = JavaInfoUtils.fromExecutable(executable, true); } catch (IOException e) { LOG.warning("Failed to lookup Java executable at " + executable, e); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/java/JavaInfo.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/java/JavaInfo.java index dc10d91b0..7f28b7464 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/java/JavaInfo.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/java/JavaInfo.java @@ -136,108 +136,6 @@ public final class JavaInfo { } } - private static final String OS_ARCH = "os.arch = "; - private static final String JAVA_VERSION = "java.version = "; - private static final String JAVA_VENDOR = "java.vendor = "; - private static final String VERSION_PREFIX = "version \""; - - public static JavaInfo fromExecutable(Path executable) throws IOException { - return fromExecutable(executable, true); - } - - public static JavaInfo fromExecutable(Path executable, boolean tryFindReleaseFile) throws IOException { - assert executable.isAbsolute(); - Path parent = executable.getParent(); - if (tryFindReleaseFile && parent != null && parent.getFileName() != null && parent.getFileName().toString().equals("bin")) { - Path javaHome = parent.getParent(); - if (javaHome != null && javaHome.getFileName() != null) { - Path releaseFile = javaHome.resolve("release"); - String javaHomeName = javaHome.getFileName().toString(); - if ((javaHomeName.contains("jre") || javaHomeName.contains("jdk") || javaHomeName.contains("openj9")) && Files.isRegularFile(releaseFile)) { - try { - return fromReleaseFile(releaseFile); - } catch (IOException ignored) { - } - } - } - } - - String osArch = null; - String version = null; - String vendor = null; - Platform platform = null; - - String executablePath = executable.toString(); - - Process process = new ProcessBuilder(executablePath, "-XshowSettings:properties", "-version").start(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), OperatingSystem.NATIVE_CHARSET))) { - for (String line; (line = reader.readLine()) != null; ) { - - int idx = line.indexOf(OS_ARCH); - if (idx >= 0) { - osArch = line.substring(idx + OS_ARCH.length()).trim(); - if (version != null && vendor != null) - break; - else - continue; - } - - idx = line.indexOf(JAVA_VERSION); - if (idx >= 0) { - version = line.substring(idx + JAVA_VERSION.length()).trim(); - if (osArch != null && vendor != null) - break; - else - continue; - } - - idx = line.indexOf(JAVA_VENDOR); - if (idx >= 0) { - vendor = line.substring(idx + JAVA_VENDOR.length()).trim(); - if (osArch != null && version != null) - break; - else - //noinspection UnnecessaryContinue - continue; - } - } - } - - if (osArch != null) - platform = Platform.getPlatform(OperatingSystem.CURRENT_OS, Architecture.parseArchName(osArch)); - - // Java 6 - if (version == null) { - boolean is64Bit = false; - process = new ProcessBuilder(executablePath, "-version").start(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), OperatingSystem.NATIVE_CHARSET))) { - for (String line; (line = reader.readLine()) != null; ) { - if (version == null) { - int idx = line.indexOf(VERSION_PREFIX); - if (idx >= 0) { - int begin = idx + VERSION_PREFIX.length(); - int end = line.indexOf('"', begin); - if (end >= 0) { - version = line.substring(begin, end); - } - } - } - - if (line.contains("64-Bit")) - is64Bit = true; - } - } - - if (platform == null) - platform = Platform.getPlatform(OperatingSystem.CURRENT_OS, is64Bit ? Architecture.X86_64 : Architecture.X86); - - if (version == null) - throw new IOException("Cannot determine version"); - } - - return new JavaInfo(platform, version, vendor); - } - public static final JavaInfo CURRENT_ENVIRONMENT = new JavaInfo(Platform.CURRENT_PLATFORM, System.getProperty("java.version"), System.getProperty("java.vendor")); private final Platform platform; diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d2fcd1d61..e395c761f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,6 +14,7 @@ chardet = "2.5.0" twelvemonkeys = "3.12.0" jna = "5.17.0" pci-ids = "0.4.0" +java-info = "1.0" # plugins shadow = "8.3.6" @@ -36,6 +37,7 @@ twelvemonkeys-imageio-webp = { module = "com.twelvemonkeys.imageio:imageio-webp" jna = { module = "net.java.dev.jna:jna", version.ref = "jna" } jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" } pci-ids = { module = "org.glavo:pci-ids", version.ref = "pci-ids" } +java-info = { module = "org.glavo:java-info", version.ref = "java-info" } [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }