Java 为什么jar文件在通过双击启动时没有从磁盘读取的权限?但如果从终端启动,则没有权限?

Java 为什么jar文件在通过双击启动时没有从磁盘读取的权限?但如果从终端启动,则没有权限?,java,macos,terminal,jar,adoptopenjdk,Java,Macos,Terminal,Jar,Adoptopenjdk,在新安装的Big Sur和采用OpenJDK 11的MacBook Pro(2015)上,我开发了一个用于教育目的的Java程序,该程序使用JFileChooser。我没有使用任何特定于IDE的代码。由于程序的其余部分无关紧要,下面是一个对我产生相同问题的最小示例(注意:此处仅作为示例,单击按钮将打开文件选择器,选择文件并单击确定将按钮文本更改为“确定”): 如果我通过终端启动程序(java-Test,或者用java-jar-Test.jar)编译成jar,一切正常。我可以打开文件选择器,它会在

在新安装的Big Sur和采用OpenJDK 11的MacBook Pro(2015)上,我开发了一个用于教育目的的Java程序,该程序使用JFileChooser。我没有使用任何特定于IDE的代码。由于程序的其余部分无关紧要,下面是一个对我产生相同问题的最小示例(注意:此处仅作为示例,单击按钮将打开文件选择器,选择文件并单击确定将按钮文本更改为“确定”):

如果我通过终端启动程序
java-Test
,或者用
java-jar-Test.jar
)编译成jar,一切正常。我可以打开文件选择器,它会在我的磁盘上显示我的文件和文件夹

如果我通过双击启动编译的jar,程序也会启动,但是如果我打开文件选择器,我在磁盘上看不到任何文件,因此我无法加载数据并将其保存到磁盘

由于我的Mac电脑上只有这些问题(不在Windows 10或Lubuntu Linux上),这可能是一个非常特殊的问题,因为我的Mac电脑上的Java设置错误。然而,当我安装了一个新的Big-Sur版本并采用OpenJDK 11 for Mac而不做任何更改时,我想知道这个问题是否会发生在其他想要运行我的程序的人(老师和学生)身上

那么,可能存在什么问题以及如何解决这个问题(对我和潜在的其他人而言)

我已经通过activity monitor了解到双击的jar是用JavaLauncher加载的(但我在磁盘上找不到它,也无法为此更改任何系统设置)

我也在这里寻找类似的问题。但这些主要与在错误路径上保存文件有关


很高兴能找到解决办法。谢谢你的回答

自Catalina(Big Sur之前的一个版本)以来,mac有一个近乎愚蠢的安全策略(很多评论家嘲笑这个“功能”是空洞的),每个应用程序在试图触摸磁盘时都会得到一个弹出提示,请求用户许可。每个主要文件夹(桌面、文档等,最终是整个磁盘)都有自己的弹出窗口

当您双击一个jar文件时,jar文件将“作为自己的应用程序”运行,并获得自己的弹出窗口。大概你否认过一次,或者可能有些东西坏了,那些弹出窗口没有显示出来

相反,当在终端中运行
java
时,这样产生的java进程最终会占用终端应用程序的权限(如果您不想这样做,请运行
open foo.jar
,它要求OS X运行jar,而不是
java-jar foo.jar
)。当您启动终端时,您已经获得了一个完整磁盘访问的弹出窗口,您可能对此说“是”,因此,由终端生成的shell生成的任何Java都可以正常工作

有容易的解决办法,也有困难的解决办法。解决的难题是完全“MacOSX化”您的应用程序。为此,您需要使用OpenJDK发行版中的
jlink
jpackage
。它们就在
javac
java
可执行文件的旁边。您需要进行模块化以正确使用这些工具

更难修复的原因是java桌面应用程序的官方发布模式已经改变。在过去(直到Java8),想法是:最终用户与Oracle达成协议:他们从Oracle下载java运行时(“JRE”)。Oracle将对其进行维护(如果JRE存在安全漏洞,Oracle将运行更新程序,否则将承担责任,但他们不会告诉您),然后该JRE将用于运行java应用程序。您(桌面java应用程序的开发人员)分发jar文件

这不再是它的工作方式

这就是为什么没有JRE9(azul和其他几家公司仍在生产它们;这是为了为那些还没有准备好升级他们的分发策略的人维护一个过时的分发模型。Oracle不再提供JRE,而不是自java9以来有意提供的)。新模型与几乎所有严肃的java桌面应用程序都已经在做的事情相匹配:你(应用程序的制造商)分发一个可以运行你的应用程序的JVM,而不是oracle。这样,你就不必向用户解释在哪里下载JRE(你的安装程序会这样做),你也可以确切地知道你要向他们提供的JRE版本,而不是祈祷他们拥有的任何东西都可以运行你的东西

这就是
jlink
jpackage
的全部内容。通过这种方式,您将得到一个
.app
文件,然后这将适合普通的mac应用程序:如果用户拒绝磁盘访问,并且他们稍后改变主意,他们可以像其他mac应用程序一样,将.app拖到其系统首选项窗口的安全小部件中的相应列表中。(是的,大多数用户都不知道如何做到这一点。苹果把这一部分搞糟了,java无法修复OSX在用户友好性方面的缺陷)


简单的方法?呃,坚持你目前的分销模式。不妨告诉他们如何启动终端并从那里运行
java
——你已经要求他们从OpenJDK安装,或多或少迫使他们注意保持最新:你已经把你的最终用户当作高级用户,知道如何管理自己的系统并安装复杂的软件。我也有同样的问题——几年前我写了一个适用于所有台式机的java jar应用程序,它在所有java版本、所有Mac操作系统和Windows上都运行良好,直到我将jar文件放在Big-Sur(OSX 11.2)上,在这一点上它无法读取或写入常规文件系统。就其本身而言,它默认只对/private/var中的tmp区域进行读写。。。而不是到目录c
import javax.swing.*;
import java.awt.event.*;

public class Test extends JFrame implements ActionListener {

  private JFileChooser jf;
  private JButton jb;

  public Test() {
    setSize(480,320);    
    jf = new JFileChooser();
    jf.setDialogType(JFileChooser.OPEN_DIALOG);
    jb = new JButton("CLICK ME");
    jb.addActionListener(this);
    add(jb);
    setVisible(true);
  }

  public void actionPerformed(ActionEvent e) {
    if (e.getSource().equals(jb)) {
        jf.setVisible(true);
        final int result = jf.showOpenDialog(null);
        if (result == JFileChooser.APPROVE_OPTION) {
          jb.setText("OK");
        }
    }
  }

  public static void main(String[] args) {
      new Test();
  }
}