Java: java.util.Preferences Failing

Моя программа сохраняет зашифрованные данные ключа продукта на компьютер с java.util.Preferences класс (системные настройки, а не пользовательские). Проблема в Windows и Linux (не тестировалась на OSX, но, вероятно, то же самое), если я не запускаю программу с sudo или с правами администратора, он выдает исключение или предупреждение всякий раз, когда пытается прочитать или сохранить данные.

Очевидно, что требовать от пользователя запуска программы с правами администратора нецелесообразно. Оптимально, я бы хотел, чтобы операционная система запрашивала у пользователя разрешение.

Это довольно глупо, и удаляет половину цели 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.

10 ответов

Решение

К сожалению, большинство ответов, которые вы получили здесь, неверны... по крайней мере, немного. В том смысле, что симптом лечится, а не причина.

Давайте подведем итоги. У Java Preferences есть два "дерева": дерево пользователя и дерево системы. Вы можете написать свой собственный бэкэнд в Java Preferences (так называемое хранилище резервных копий), но немногие разработчики так делают, так что в итоге вы получаете хранилище резервных копий JDK по умолчанию. На платформе Windows это означает Win Registry, а именно:

  • Дерево пользователя записано в HKEY_CURRENT_USER\Software\JavaSoft\Prefs (пользователь ОС всегда имеет доступ для записи здесь)
  • Системное дерево записывается в HKEY_LOCAL_MACHINE\Software\JavaSoft\Prefs (только пользователь ОС с правами администратора имеет право на запись здесь)

В итоге: пока ваш код не пытается использовать системное дерево, у вас все должно быть в порядке, и вам не нужно возиться с назначением привилегий на уровне ОС. Дерево системы предназначено для "всех пользователей на хосте", а дерево пользователей предназначено для конкретного вошедшего в систему пользователя. Я уверен, что в вашем случае вы можете использовать дерево пользователей, так что это действительно ваше решение. Не балуйтесь с привилегиями, работайте от имени администратора, а что нет.

.... но это еще не все. Предположим, что ваш код намеренно не касается дерева системы Java Preferences, как указано в инструкции. Затем вы все равно увидите это предупреждение в Windows:

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

Так, что происходит? Я дал тебе неправильный совет? На самом деле, нет. Останься со мной.

Погрузившись в исходный код JDK, вы увидите, что 0x80000002 означает HKLM, то есть место в реестре Win, которое не должно быть затронуто. Ваш код никогда не ссылается на системное дерево, и все же вы видите это предупреждение!?? (В этот момент вы, должно быть, рвали все свои волосы... как я)

Ну, это один из редких случаев, когда действительно есть ошибка JDK. Вы можете прочитать больше об этом в моем ответе, который я рекомендую вам прочитать, если вас интересует, почему тонкие ошибки могут оставаться незамеченными в JDK в течение многих лет. Ошибка существует со времен JDK 1.4, но только недавно была исправлена ​​и еще не перенесена в JDK 8.

Лучший совет

  • Убедитесь, что ваш код ссылается только на дерево пользователей, а не на системное дерево. Справедливо, что ОС требует всех видов привилегий для записи в общесистемное местоположение. Если вам действительно нужно записать в такое место, то на самом деле нет другого решения, кроме назначения привилегий, выполнения от имени администратора или чего-то еще.
  • Не обращайте внимания на предупреждение. Он исчезнет, ​​как только вы перейдете на Java 9 или когда Oracle решит перенести исправление ошибки в Java 8. Предупреждение можно смело игнорировать.
  • В качестве альтернативы вы можете попытаться программно игнорировать предупреждение. Это исходит от JDK Platform Logger, поэтому что-то вроде этого должно работать, хотя я сам не пробовал:

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

Эта ссылка работает для меня:

Решение проблемы Временное решение: войти в систему как administrator и создать ключ HKEY_LOCAL_MACHINE\Software\JavaSoft\Prefs

Можно изменить права доступа к записям реестра. Если вы разрешите права полного доступа к HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs для всех, каждый увидит один и тот же набор предпочтений, и каждый сможет изменить их глобально. Я знаю, что это не решение для программного обеспечения, устанавливаемого клиентами, но оно может быть полезно для кого-то.

Изменение ответа на основе обратной связи. Это решение, вероятно, излишне, но...

  • Я предлагаю вам изменить свой магазин, чтобы записать в файл вместо реестра ( пример)
  • Многие Java-продукты поставляются с собственной JVM. Они делают это так, что могут работать с настраиваемым файлом политики (который в вашем случае понадобится для записи в общее местоположение) и экономить на проблемах поддержки (таких как использование устаревшей / непроверенной JVM)

В частности, в Windows 7 JVM по умолчанию не имеет разрешения на запись в реестр Windows, где хранилище резервных копий для java.util.prefs.preferences находится под MS-Windows.

При выполнении или преобразователя ReverseXSL, или даже программы-тестера Regex, могут появляться такие ошибки, как: Не удалось открыть / создать корневой узел prefs Software\JavaSoft\Prefs в корне 0x80000002. Windows RegCreateKeyEx

Это мешает регистрации лицензии. Это не мешает программному обеспечению выполнять преобразования в режиме свободного программного обеспечения.

Исправление проблемы - это просто вопрос предоставления необходимых разрешений корневому ключу реестра.

Запустите regedit.exe от имени администратора (regedit.exe находится в корневом каталоге операционной системы c:\Windows). Перейдите к ключу HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs. Щелкните правой кнопкой мыши, чтобы установить разрешения. Установите флажок в поле Полный доступ для пользователей, которым необходимо запустить программное обеспечение reverseXSL.

Просто запустите приложение от имени администратора или, если вы используете eclipse, запустите eclipse от имени администратора.

Наконец, это было исправлено в январе 2019 года в Java SE Development Kit 8u202.

Это обновление набора исправлений (PSU), в отличие от критического обновления исправлений (CPU), 8u201. Разница объясняется здесь. (Страница использует Java 7 в качестве примера, но она все понимает.)

Загрузку можно найти ниже на странице "Java SE Development Kit 8". ( https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)

Ответ от peterh уже подробно описан на заднем плане, но я искал исправление и нашел его!

Так как вы не можете коснуться самого PlatformLogger, вы должны аннулировать его сообщение:

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

Таким образом, надоедливое Предупреждение исчезло, не оставив никаких следов. Обратите внимание, что вам нужно сделать это только в тот момент, когда вы впервые ссылаетесь на API настроек в своей программе.

Исправление состоит в том, чтобы запустить JMeter от имени администратора, он создаст для вас ключ реестра, затем вы можете перезапустить JMeter как обычный пользователь, и у вас больше не будет предупреждений. Официальный сайт JMeter - изменения

Решение для меня было неочевидным - оно состояло в том, чтобы обновить мои файлы безопасности для криптографии из Oracle, так как это похоже на ограничение длины ключа (я не верил, что это связано, пока не попробовал).

Скачать с сайта Oracle

Загрузка содержит инструкции и объясняет:

Из-за ограничений контроля импорта в некоторых странах версия файлов политики JCE, связанных в среде выполнения Java или среде JRE, позволяет использовать "сильную", но ограниченную криптографию. Этот пакет загрузки (включающий этот файл README) предоставляет файлы политик "неограниченной силы", которые не содержат ограничений на силу криптографии.

Это очевидно относится и к ключам реестра

Зайдите в свой реестр и создайте JavaSoft\Prefs\myapp под HKEY_LOCAL_MACHINE-->SOFTWARE

Создайте имя ключа как Prefs и в этом создайте дополнительный ключ как myapp, это решит проблему.

Другие вопросы по тегам