5

我构建了一个相当大的 JavaFX 应用程序(JAR 大约 128 MB),并且通过 IntelliJ 运行没有问题。但是当我从终端运行它时,我的 3D 模型加载器(Fxyz3d 库)会启动此异常。

Exception in thread "JavaFX Application Thread" java.nio.file.FileSystemNotFoundException
    at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:172)
    at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider.java:158)
    at java.base/java.nio.file.Path.of(Path.java:208)
    at java.base/java.nio.file.Paths.get(Paths.java:98)
    at org.fxyz3d.importers.obj.ObjImporter.read(ObjImporter.java:115)
    at org.fxyz3d.importers.obj.ObjImporter.loadAsPoly(ObjImporter.java:102)
    at org.fxyz3d.importers.Importer3D.loadIncludingAnimation(Importer3D.java:160)
    at org.fxyz3d.importers.Importer3D.loadAsPoly(Importer3D.java:80)
    at it.polimi.ingsw.PSP50.View.GUI.GuiView.lambda$startingGame$1(GuiView.java:201)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96) 

这仅适用于 Fxyz3d 库中的 3D 对象加载器,而不适用于我的其他普通 FXML 加载器。我使用相同的方式从我的 src/main/resources 文件夹中获取文件,即 getClass().getResource。那么这真的是路径问题吗?还是图书馆的问题?相反,在 IntelliJ 中完全没有问题,一切正常。这是代码中不起作用的部分:

Model3D boardModel = Importer3D.loadAsPoly(getClass().getResource("/boardcliff2.obj"));
 

如果有人以前遇到过这样的事情并且知道发生了什么,我们将不胜感激

4

2 回答 2

3

José Pereda 为此打开了一个问题,该问题已得到修复。截至目前(2020 年 8 月 14 日),FXyz 的最新版本为 0.5.2,其中不包含此问题的修复程序。您可以继续使用此答案中显示的解决方法,从最近的提交中自己构建库,或者等待库的下一个版本。


这似乎是实施的问题。它试图将 转换URL为 aPath但必要的FileSystem不存在1。最好的解决方法可能是将资源提取到临时文件中,然后从所述文件中导入对象。这样,URL 将具有file:协议并且转换Path将起作用(默认值FileSystem始终存在)。这是一个如何提取资源的示例:

// Note: 'Path' is 'java.nio.file.Path', not 'javafx.scene.shape.Path'
public static Path copyToTempFile(URL url, String suffix) throws IOException {
  // 'suffix' will default to ".tmp" if null
  Path tempFile = Files.createTempFile(null, suffix);
  try (InputStream in = url.openStream();
       OutputStream out = Files.newOutputStream(tempFile)) {
    in.transferTo(out); // 'transferTo' method added in Java 9
  }
  return tempFile;
}

然后您可以使用结果Path导入 3D 对象:

Path tempFile = copyToTempFile(getClass().getResource("/boardcliff2.obj"), ".obj");
Model3D boardModel = Importer3D.loadAsPoly(tempFile.toUri().toURL());

如果需要,您可以在完成后删除临时文件。


1. 当嵌入到 JAR 文件中时,资源的 URL 具有jar:协议。这意味着FileSystem来自ZIP FileSystemProvider的、打开到特定 ZIP/JAR 文件的文件必须存在才能进行转换Path。如果实现简单地使用 ,则不会发生此问题URL#openStream(),它通过不同的机制访问 JAR 条目。

于 2020-06-28T04:34:32.393 回答
0

除了 Slaw 的解决方案之外,我的一位同事还找到了一个替代解决方案:将这些代码行添加到 ObjImporter 类(Fxyz3d 库)中的函数 loadAsPoly 中,解决了每次导入的问题。

public class ObjImporter implements Importer {
    ...
    @Override
    public Model3D loadAsPoly(URL url) throws IOException {
        // Additional lines
             if(url.getProtocol().equals("jar")) {
                            try {
                                Map<String, String> env = new HashMap<>();
                                env.put("create", "true");
                                FileSystem zipfs = FileSystems.newFileSystem(url.toURI(), env);
                            } catch(FileSystemAlreadyExistsException ignored) {

                            } catch (IOException | URISyntaxException e) {
                                e.printStackTrace();
                            }
                        }
        // End of the addition
        return read(url, true);
    }
   ...
}

我用我的 Jar 对其进行了测试,它也可以正常工作(当然,在我的项目中,我将 Fxyz 库中的必要类导入到我的 Utils 包中)。

于 2020-06-28T15:16:54.190 回答