“找不到 jar 文件系统提供程序”尝试使用 jdeps 和 jlink 创建收缩 Java 映像来运行 Minecraft

2024-04-26

我正在尝试使用以下命令创建一个收缩 Java 映像来运行 Minecraft 1.20.1 客户端jdeps and jlink(即只需要运行 Minecraft 所需的最少 Java 模块),但是我遇到了错误,我希望得到一些指导。这就是我所做的:

我下载了列出的库1.20.1 清单 https://piston-meta.mojang.com/v1/packages/cdad018fbbe4e10919b560da3d1640d7b6355dbf/1.20.1.json进入我的 ~/.minecraft/libraries 和client.jar在 ~/.minecraft/versions/1.20.1/1.20.1.jar 中。

为了查找 Minecraft 客户端使用的 Java 模块,我运行了:

jdeps \
    -q \
    --ignore-missing-deps \
    --print-module-deps \
    --multi-release 17 \
    -cp $HOME'/.minecraft/libraries/*' \
    --recursive \
    $HOME/.minecraft/versions/1.20.1/1.20.1.jar

这给了我:

java.base,java.compiler,java.desktop,java.management,java.naming,java.rmi,java.scripting,java.security.jgss,java.sql,jdk.jfr,jdk.unsupported

然后我将这些模块传递给jlink as $modules:

jlink --no-header-files --compress=2 --no-man-pages --add-modules $modules --output 'custom-jre'

最后,我像往常一样运行 Minecraft 客户端,但现在使用我新创建的收缩 JVM

/path/to/custom-jre/bin/java \
    -cp '<whole-list-of-minecraft-jars>' \
    net.minecraft.client.main.Main \
    --version 1.20.1 \
    --gameDir $HOME/.minecraft \
    --accessToken <auth-token>

崩溃并显示错误消息:

Exception in thread "main" java.lang.ExceptionInInitializerError
        at net.minecraft.client.main.Main.main(SourceFile:83)
Caused by: java.lang.IllegalStateException: No jar file system provider found
        at ac.o(SourceFile:101)
        at java.base/java.util.Optional.orElseThrow(Optional.java:403)
        at ac.<clinit>(SourceFile:101)
        ... 1 more

正如您所看到的,客户端成功启动,但 Minecraft 源代码中的某个时刻存在未处理的异常。

Using MCP https://github.com/Hexeption/MCP-Reborn(《我的世界》源代码的反编译版本)我设法找到了引发错误的相关代码:

// src/main/java/net/minecraft/Util.java

public class Util {
   // ....

   public static final FileSystemProvider ZIP_FILE_SYSTEM_PROVIDER = FileSystemProvider.installedProviders().stream().filter((p_201865_) -> {
      return p_201865_.getScheme().equalsIgnoreCase("jar");
   }).findFirst().orElseThrow(() -> {
      return new IllegalStateException("No jar file system provider found");
   });

   // ....
}

我对Java文件系统不是很熟悉,但是基本上找不到“jar”文件系统提供者。我写了这段最小的代码来说明问题:

import java.nio.file.spi.FileSystemProvider;

public class Test {
    public static void main(String[] args) {
        for (var provider : FileSystemProvider.installedProviders()) {
            System.out.println(provider.getScheme().toString());
        }
    }
}
# Running with the system's JDK 17.0.8 (~259M)
$ java Test
file
jar
jrt

# Running it with my custom JRE: (~58M)
$ /path/to/custom-jre/bin/java Test
file
jrt # <- doesn't have the jar file system

我在这里描述的方法适用于我拥有的每个项目,只有 Minecraft 导致了这个问题。如果有更好的方法,我很乐意看到!

那么什么是合适的解决方案呢?我错过了什么吗? “jar 文件系统”在哪里定义的?欢迎任何帮助,提前致谢:)


添加模块jdk.zipfs在您的列表中,应该提供 zip 文件系统。

另请参阅jdk.zipfs https://docs.oracle.com/en/java/javase/20/docs/api/jdk.zipfs/module-summary.html文档并检查是否jdeps帮助您缩小更多依赖关系的范围。

UPDATE

您似乎已经使用过jdeps正确地分析模块依赖关系,但不幸的是它无法帮助动态代码依赖关系,例如基于反射、服务或其他类加载。

您可以使用jdeps没有摘要依赖关系--print-module-deps打印更详细的列表,这可能会提示依赖模块内的包中的服务提供者 - 例如java.nio.file.spi此处显示:

jdeps .....  your.jar
your.jar -> java.base
   ...
   some.module.name     -> java.nio.file.spi      java.base

您可以通过搜索上面链接的 JDK 文档中的包名称来找到提供程序名称。然后你可以使用一个选项jlink建议缺少的服务提供商实施,例如java.nio.file.spi.FileSystemProvider:

jlink --suggest-providers java.nio.file.spi.FileSystemProvider

Suggested providers:
  java.base provides java.nio.file.spi.FileSystemProvider used by java.base
  jdk.zipfs provides java.nio.file.spi.FileSystemProvider used by java.base

另一个经常导致 jlink 打包问题的缺失提供程序是代码需要额外的字符集支持:

jlink --suggest-providers java.nio.charset.spi.CharsetProvider
Suggested providers:
   jdk.charsets provides java.nio.charset.spi.CharsetProvider used by java.base
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

“找不到 jar 文件系统提供程序”尝试使用 jdeps 和 jlink 创建收缩 Java 映像来运行 Minecraft 的相关文章

  • Java 中如何将 long 转换为 int?

    Java 中如何将 long 转换为 int 在 Java 8 中更新 Math toIntExact value 原答案 简单的类型转换应该可以做到 long l 100000 int i int l 但请注意 较大的数字 通常大于214
  • 从 Hibernate 生成 SQL 脚本

    我正在为我的 Java Swing 应用程序使用 Hibernate 4 3 5 Final 并且我做了很多工作UDPATE INSERT and DELETE与它 在 HQL 中或与Criteria 现在 我想做的是导出对数据库所做的所有
  • “android.enableUnitTestBinaryResources”已弃用[重复]

    这个问题在这里已经有答案了 我刚刚更新了我的 Android Studio 现在当我构建我的项目时 我收到此错误 选项 android enableUnitTestBinaryResources 已弃用 这 当前默认值为 假 已从当前版本中
  • Maven:在项目之间共享源

    我有两个项目 它们是一个共同父项目的子项目 还有一个生成器项目和生成器对应的maven插件项目 此外 两个子项目都使用相同的输入文件 该文件用于代码生成 parent pom child1 jar src main generator in
  • 禁用特定的 ServletContextListener 以防止在 tomcat 上启动

    我的项目正在使用spring boot with webflux tomcat 我有一个内部库类 它是ServletContextListener WebListener public class DevIoServletContextLi
  • Glide:如何使用 Glide v4 调整 gif 大小并将其另存为文件?

    我想调整 gif 文件的大小并保存它 我尝试使用一些建议的方法 但这些方法给出了错误 后来我知道有些方法在 Glide 中已被弃用v4 byte bytes Glide with context asGif load url toBytes
  • Java心跳设计

    我需要在我的 Java 项目上实现一个心跳系统 3 5 个客户端和 1 个服务器 但我有一些问题 1 客户端需要有 2 个套接字吗 1 用于心跳 1 用于接收我的软件的正常消息 2 我看到在特定情况下 当客户端滞后时 客户端不会收到消息 如
  • 何时使用环境变量与系统属性?

    我想知道以下哪种方法是首选方法 我们可以将事情设置为APP HOME path to file export in profile或类似的东西 并将其访问为System getenv APP HOME 或者 也可以使用属性作为 DAPP H
  • Selenium 2:中断页面加载

    我在使用 FirefoxDriver 使用 Selenium 2 0b3 Java API 单击按钮时遇到问题 单击该按钮会将表单发送到网络服务器 然后浏览器会因表单提交而进入新页面 当使用 element click 单击某个元素时 se
  • Apache POI - JAVA - 迭代 Excel 中的列

    这里是java新手 我正在编写一个代码 该代码读取 Excel 文件 查看列中的单元格 然后编写如下表所示的内容 我有一个 Excel 文件 如下所示 col1 col2 col3 col4 row1 2 3 1 1 w row2 3 2
  • Java中的字符算术

    在玩的过程中 我遇到了一些对我来说似乎很奇怪的事情 以下不是有效的 Java 代码 char x A x x 1 possible loss of precision 因为其中一个操作数是整数 所以另一个操作数被转换为整数 结果无法分配给字
  • 当从搜索表单动态构建 WHERE 子句时,如何防止 SQL 注入?

    我知道在 Java 中保护 SQL 查询免受 SQL 注入的唯一真正正确的方法是使用准备好的语句 然而 这样的语句要求基本结构 选择的属性 连接的表 WHERE条件的结构 不会改变 我这里有一个 JSP 应用程序 其中包含一个带有大约十几个
  • Java TreeMap时间复杂度-lowerKey

    时间复杂度是多少lowerKey Java实现中的操作TreeMap 我认为它是 log n 但我在文档中找不到它 更基本操作的复杂性已有详细记录 此实现提供了有保证的 log n 时间成本 containsKey 获取 放置和删除操作 顺
  • 如何从java程序中编译.java文件[重复]

    这个问题在这里已经有答案了 可能的重复 从 Java 内部编译外部 java 文件 https stackoverflow com questions 10889186 compiling external java files from
  • java中类的命名约定 - 全部大写

    在 Java 中 当类全部大写时 如何命名它 例如 如果我想创建一个班级来选择某些人成为 VIP 我应该将类命名为 VIPSelector 还是 VipSelector Thanks 你的两个选择都有效 类的主要目标是让它们以大写字母开头
  • 如何在 JUnit5 中为测试套件设置自定义测试执行顺序?

    我在 JUnit5 上进行了大量测试 并在多个线程中并行运行 还有有关每次测试时间的信息 我想在最长的测试开始时运行 并将最快的测试留在最后以优化公共执行时间 我还没有找到在 JUnit5 中执行此操作的方法 版本中5 4有一个org ju
  • 蓝牙连接;无法正确发送字符串

    当我需要将字符串从服务器蓝牙套接字发送到客户端蓝牙套接字时 我的程序遇到了麻烦 只要我一次只发送一个字符串 例如聊天 一切都可以正常工作 但是如果我需要在短时间内编写更多字符串 以交换信息 则字符串将不会与客户端代码分离 例如 如果我发送
  • 遍历多行字符串

    我得到一些数据 def data some useless text n even more n finally interesting text 我怎样才能得到其中 有趣的部分 所以基本上所有行都不是以 开头的 Groovy 的一种选择是
  • Spring Data 中 IQueryable 的等效项

    我习惯了 Net 和 LINQtoEntities 尤其是 IQueryable 部分 它允许在获取结果之前通过不同的函数传送请求 Spring数据中是否存在类似的东西 或者任何其他 java ORM 我希望能够做的基本示例 private
  • struts2中如何访问url参数

    我正在做一个struts2项目 我在项目中创建了 url 并使用标签传递了参数 我的问题是如何读取操作中的参数 另外 如果执行相同的操作 我将能够将参数视为查询字符串 我问是因为我无法做到 而且我在其中一个教程中看到了它 通常 您将通过使用

随机推荐