Java:java.util.Preferences失败

我的程序使用java.util.Preferences类(系统首选项,不是用户)将encryption的产品密钥数据保存到计算机java.util.Preferences 。 问题是,在Windows和Linux上(没有在OSX上testing,但可能是相同的),如果我不用sudo或pipe理员权限运行程序,它会尝试读取时发出exception或警告或保存数据。

显然要求用户以pipe理员权限运行程序是不切实际的。 最好,我希望操作系统要求用户许可。

这非常愚蠢,并删除了Preferences一半目的。 这怎么解决?

下面是我需要的摘要 :我需要我的程序从操作系统请求权限以保存系统设置。


这是错误信息

下面是我尝试读取节点时的错误(因为节点不存在):

 Mar 18, 2011 9:41:15 AM java.util.prefs.WindowsPreferences <init> WARNING: Could not create windows registry node Software\JavaSoft\Prefs\myapp at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5. Mar 18, 2011 9:41:15 AM java.util.prefs.WindowsPreferences WindowsRegOpenKey1 WARNING: Trying to recreate Windows registry node Software\JavaSoft\Prefs\myapp at root 0x80000002. Mar 18, 2011 9:41:15 AM java.util.prefs.WindowsPreferences openKey WARNING: Could not open windows registry node Software\JavaSoft\Prefs\myapp at root 0x80000002. Windows RegOpenKey(...) returned error code 2. Mar 18, 2011 9:41:15 AM java.util.prefs.WindowsPreferences WindowsRegOpenKey1 WARNING: Trying to recreate Windows registry node Software\JavaSoft\Prefs\myapp\subpackage at root 0x80000002. Mar 18, 2011 9:41:15 AM java.util.prefs.WindowsPreferences openKey WARNING: Could not open windows registry node Software\JavaSoft\Prefs\myapp\subpackage at root 0x80000002. Windows RegOpenKey(...) returned error code 2. 

这是当我尝试写入节点时发生的情况:

 Mar 18, 2011 9:43:11 AM java.util.prefs.WindowsPreferences WindowsRegOpenKey1 WARNING: Trying to recreate Windows registry node Software\JavaSoft\Prefs\myapp\subpackage at root 0x80000002. Mar 18, 2011 9:43:11 AM java.util.prefs.WindowsPreferences openKey WARNING: Could not open windows registry node Software\JavaSoft\Prefs\myapp\subpackage at root 0x80000002. Windows RegOpenKey(...) returned error code 2. 

不幸的是,你在这里得到的答案大部分是错误的…至less有点。 在症状正在治疗的意义上,而不是原因。

让我们回顾一下。 Java首选项有两个“树”: 用户树和系统树 。 您可以将自己的后端编写到Java首选项(称为后备存储),但很less有开发人员这样做,因此您最终得到了JDK的默认后备存储。 在Windows平台上,这意味着Winregistry,更具体地说:

  • 用户树被写入到HKEY_CURRENT_USER\Software\JavaSoft\Prefs (操作系统用户在这里总是有写权限)
  • 系统树被写入HKEY_LOCAL_MACHINE\Software\JavaSoft\Prefs (只有一个具有pipe理权限的操作系统用户在这里有写权限)

总之:只要你的代码不尝试使用系统树,你应该没问题,不应该在操作系统级别上分配权限。 系统树意味着“主机上的所有用户”,而用户树意味着特定的login用户。 在你的情况下,我相信你可以满足用户树,所以这真的是你的解决scheme。 不要去搞特权,以pipe理员身份运行,什么不是。

….但还有更多。 假设您的代码按照指示故意不碰触Java首选项系统树。 您将在Windows上看到这个警告:

 WARNING [java.util.prefs]: Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5. 

那么发生了什么? 我给了你错误的build议吗? 不是真的。 跟我在一起。

潜入JDK源代码中,您将看到0x80000002意味着HKLM,即Win Registry中不应该被触及的地方。 你的代码永远不会引用系统树,但你仍然看到这个警告! (在这一点上,你必须把你所有的头发都撕掉……就像我一样)

那么,这是真正存在JDK错误的罕见情况之一。 您可以在我的答案中阅读更多关于它的信息,如果您对为什么微软漏洞可能在JDK中未被发现多年感兴趣,我鼓励您阅读。 这个bug自从JDK 1.4以来一直存在,但是最近才被修复,并没有被移植到JDK 8。

最好的build议

  • 确保你的代码只引用用户树,而不是系统树。 操作系统需要各种权限才能写入系统范围,这是公平的。 如果你真的需要写入这样一个位置,那么真的没有其他的解决scheme,而不是分配特权,以pipe理员身份执行或不执行。
  • 忽略警告。 一旦使用Java 9,或者Oracle决定将错误修复程序恢复到Java 8时,它就会消失。警告可以安全地忽略。
  • 或者,您可以尝试以编程方式忽略该警告。 它来自JDK的平台logging器,所以类似这样的应该工作,虽然我没有尝试过自己:

     sun.util.logging.PlatformLogger platformLogger = PlatformLogger.getLogger("java.util.prefs"); platformLogger.setLevel(PlatformLogger.Level.OFF); 

这个链接对我来说是工作的:

解决问题解决方法是以administrator身份login并创build密钥HKEY_LOCAL_MACHINE\Software\JavaSoft\Prefs

可以更改registry项的访问权限。 如果您对每个人都允许对HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs完全访问权限,每个人都将看到相同的一组首选项,并且每个人都可以在全局范围内进行更改。 我知道这不是一个由客户安装的软件的解决scheme,但它可能是有用的。

根据反馈修改答案。 这个解决scheme可能是矫枉过正的,但…

  • 我build议你改变你的商店写入文件,而不是registry( 例如 )
  • 很多基于Java的产品都带有自己的JVM。 他们这样做,使他们可以运行一个自定义的策略文件(这将需要你的情况下写入一个共同的位置),并保存在支持问题(如过时/未经testing的JVM正在使用)

特别是对于Windows 7,JVM并没有默认权限写入MS-Windows下的java.util.prefs.preferences的后备存储所在的Windowsregistry中。

当执行ReverseXSL转换器,甚至正则expression式testing程序时,可能会出现如下错误:无法在根0x80000002处打开/创build首选项根节点Software \ JavaSoft \ Prefs。 Windows RegCreateKeyEx

这确实会阻止注册许可证。 它不会阻止软件在自由软件模式下执行转换。

解决这个问题仅仅是为registry根密钥授予必要的权限。

以pipe理员身份运行regedit.exe(regedit.exe位于c:\ Windows操作系统根目录下)。 转到HKEY_LOCAL_MACHINE \ SOFTWARE \ JavaSoft \ Prefs项。 右键单击设置权限。 在“完全控制”checkbox中选中需要执行reverseXSL软件的用户。

只需以pipe理员身份运行应用程序,或者如果使用eclipse,请以pipe理员身份运行eclipse。

解决方法是以pipe理员身份运行JMeter,它将为您创buildregistry项,然后您可以以普通用户身份重新启动JMeter,并且不会再有警告。 JMeter官方网站 – 变化

对我来说这个解决scheme并不明显 – 它是从Oracle更新我的encryption安全瓶,因为它似乎是一个关键的长度限制(我不相信这是相关的,直到我试了一下)。

从Oracle网站下载

下载包含说明并解释:

由于某些国家的import控制限制,捆绑在Java运行时环境或JRE(TM)8环境中的JCE策略文件的版本允许使用“强”但有限的密码术。 这个下载包(包括这个README文件)提供了“无限强度”策略文件,其中不包含对encryption强度的限制。

这显然也适用于registry项

peterh的答案已经阐述了背景,但我正在寻找一个修复,并find它!

由于您无法触摸PlatformLogger本身,您必须使其消息无效:

 // get rid of the bugged Preferences warning System.setErr(new PrintStream(new OutputStream() { public void write(int b) throws IOException {} })); PREFS = Preferences.userNodeForPackage(Settings.class); System.setErr(System.err); 

这样恼人的警告消失了,没有留下任何痕迹。 请注意,您只需要在程序中首次引用Preferences API的位置执行此操作。