Как установить переменные окружения из Java? Я вижу, что я могу сделать это для использования подпроцессов ProcessBuilder
. У меня есть несколько подпроцессов для запуска, поэтому я бы предпочел изменить среду текущего процесса и позволить подпроцессам наследовать ее.
Есть System.getenv(String)
для получения одной переменной среды. Я также могу получить Map
полный набор переменных окружения с System.getenv()
. Но, призывая put()
к этому Map
бросает UnsupportedOperationException
- очевидно, они означают, что среда должна быть только для чтения. И нет System.setenv()
.
Итак, есть ли способ установить переменные среды в текущем процессе? Если да, то как? Если нет, в чем смысл? (Это потому, что это Java, и поэтому я не должен делать злых непереносимых устаревших вещей, таких как прикосновение к моей среде?) И если нет, то любые полезные предложения по управлению изменениями переменных среды, которые я собираюсь передать нескольким подпроцессы?
источник
Ответы:
Я думаю, что ты ударил гвоздь по голове.
Возможный способ облегчить бремя - это выделить метод
и передайте любые
ProcessBuilder
s через это прежде, чем начать их.Кроме того, вы, вероятно, уже знаете это, но вы можете запустить более одного процесса с одним и тем же
ProcessBuilder
. Так что, если ваши подпроцессы одинаковы, вам не нужно делать это снова и снова.источник
Для использования в сценариях, где вам нужно установить конкретные значения среды для модульных тестов, вам может пригодиться следующий хак. Это изменит переменные окружения во всей JVM (поэтому убедитесь, что вы сбросили все изменения после теста), но не изменит вашу системную среду.
Я обнаружил, что комбинация двух грязных хаков Эдварда Кэмпбелла и анонимного работает лучше всего, поскольку один из них не работает в Linux, а другой не работает в Windows 7. Поэтому, чтобы получить многоплатформенный злой хак, я объединил их
Это работает как шарм. Полные кредиты двум авторам этих хаков.
источник
import java.lang.reflect.Field;
Или добавить / обновить одну переменную и удалить цикл согласно предложению thejoshwolfe.
источник
Class<?> cl = env.getClass();
вместо этого для цикла?источник
в Android интерфейс представлен через Libcore.os как своего рода скрытый API.
Класс Libcore, а также интерфейс ОС являются общедоступными. Просто объявление класса отсутствует и должно быть показано компоновщику. Не нужно добавлять классы в приложение, но это также не повредит, если оно включено.
источник
throws ErrnoException
наthrows Exception
.Os.setEnv
сейчас. developer.android.com/reference/android/system/… , java.lang.String, boolean)Только Linux
Установка отдельных переменных среды (на основе ответа Эдварда Кэмпбелла):
Использование:
Во-первых, поместите метод в любой класс, который вы хотите, например, SystemUtil. Затем назовите это статически:
Если вы позвоните
System.getenv("SHELL")
после этого, вы"/bin/bash"
вернетесь.источник
Это комбинация ответа @ paul-blair, преобразованного в Java, который включает в себя некоторые исправления, указанные Полом Блэром, и некоторые ошибки, которые, похоже, были внутри кода @pushy, который состоит из @Edward Campbell и anonymous.
Я не могу подчеркнуть, насколько этот код должен использоваться ТОЛЬКО в тестировании, и он очень хакерский. Но для случаев, когда вам нужна настройка среды в тестах, это именно то, что мне нужно.
Это также включает в себя некоторые мелкие штрихи, которые позволяют коду работать на обеих Windows, работающих на
а также Centos работает на
Реализация:
источник
Оказывается, решение от @ pushy / @ anonymous / @ Edward Campbell не работает на Android, потому что Android на самом деле не Java. Конкретно у Android нет
java.lang.ProcessEnvironment
вообще. Но в Android это оказывается проще, вам просто нужно сделать JNI-вызов в POSIXsetenv()
:В C / JNI:
И на Яве:
источник
Как и большинство людей, которые нашли этот поток, я писал некоторые модульные тесты, и мне нужно было изменить переменные среды, чтобы установить правильные условия для выполнения теста. Тем не менее, я обнаружил, что ответы с наибольшим количеством голосов имели некоторые проблемы и / или были очень загадочными или чрезмерно сложными. Надеюсь, это поможет другим быстрее разобраться в решении.
Во-первых, я наконец нашел решение @Hubert Grzeskowiak самым простым, и оно сработало для меня. Я хотел бы прийти к этому первым. Это основано на ответе Эдварда Кэмпбелла, но без усложнения циклического поиска.
Однако я начал с решения @ pushy, которое получило наибольшее количество голосов. Это комбинация @anonymous и @Edward Campbell's. @pushy утверждает, что оба подхода необходимы для охвата как среды Linux, так и Windows. Я работаю под OS X и обнаружил, что оба работают (как только проблема с подходом @anonymous решена). Как уже отмечали другие, это решение работает большую часть времени, но не все.
Я думаю, что источником большей части путаницы является решение @ anonymous, работающее в области «TheEnvironment». Глядя на определение структуры ProcessEnvironment , «theEnvironment» - это не карта <String, String>, а карта <переменная, значение>. Очистка карты работает нормально, но операция putAll перестраивает карту Map <String, String>, что потенциально вызывает проблемы, когда последующие операции работают с структурой данных с использованием обычного API, который ожидает Map <Variable, Value>. Кроме того, доступ / удаление отдельных элементов является проблемой. Решение состоит в том, чтобы получить доступ к «Среде» косвенно через «Немодифицируемую Среду». Но так как это тип UnmodifiableMapдоступ должен быть сделан через закрытую переменную 'm' типа UnmodifiableMap. Смотрите getModifiableEnvironmentMap2 в коде ниже.
В моем случае мне нужно было удалить некоторые переменные окружения для моего теста (остальные должны быть неизменными). Затем я хотел восстановить переменные среды до их прежнего состояния после теста. Процедуры ниже делают это прямо вперед, чтобы сделать. Я протестировал обе версии getModifiableEnvironmentMap на OS X, и обе работают одинаково. Хотя на основе комментариев в этой теме, один может быть лучшим выбором, чем другой, в зависимости от среды.
Примечание: я не включил доступ к 'theCaseInsensitiveEnvironmentField', так как это, похоже, специфично для Windows, и у меня не было возможности проверить его, но добавить его было бы просто.
источник
Перебирая онлайн, похоже, что это возможно сделать с JNI. Затем вам нужно будет вызвать функцию putenv () из C, и вам (предположительно) придется сделать это так, чтобы это работало как в Windows, так и в UNIX.
Если бы все это можно было сделать, то для самой Java, конечно, было бы не слишком сложно это поддержать, вместо того, чтобы поставить меня в смирительную рубашку.
Друг, говорящий на Perl, предполагает, что это происходит потому, что переменные среды являются глобальными процессами, а Java стремится к хорошей изоляции для хорошего дизайна.
источник
LD_LIBRARY_PATH
перед вызовомRuntime.loadLibrary()
;dlopen()
вызов, который он вызывает, смотрит на реальную среду, а не на идею Java того же самого).Попробовал ответ Пуши выше и это сработало по большей части. Однако в определенных обстоятельствах я бы увидел это исключение:
Это происходит, когда метод вызывался более одного раза, благодаря реализации некоторых внутренних классов метода.
ProcessEnvironment.
ЕслиsetEnv(..)
метод вызывается более одного раза, когда ключи извлекаются изtheEnvironment
карты, они теперь являются строками (будучи помещенными в в виде строк при первом вызовеsetEnv(...)
) и не может быть приведен к универсальному типу карты,Variable,
который является частным внутренним классомProcessEnvironment.
Фиксированная версия (в Scala), ниже. Надеюсь, это не так сложно перенести на Java.
источник
import java.lang.{Class => JavaClass}
.Это версия Kotlin злой ответ @ Pushy's злой =)
Это работает в MacOS Mojave по крайней мере.
источник
Если вы работаете с SpringBoot, вы можете добавить указание переменной среды в следующем свойстве:
источник
Jythonвариант, основанный на ответе @ pushy , работает на windows.
Использование:
источник
Ответ Тима Райана работал для меня ... но я хотел его для Groovy (например, для контекста Спока) и по-простому:
источник
Версия в Kotlin, в этом алгоритме я создал декоратор, который позволяет устанавливать и получать переменные из среды.
источник
Реализация Kotlin, которую я недавно сделал, основываясь на ответе Эдварда:
источник
Вы можете передать параметры в исходный процесс Java с помощью -D:
источник
System.getProperty
и не совпадают сSystem.getenv
. Кроме того,System
класс также позволяет устанавливать эти свойства статически, используяsetProperty