Как установить переменные окружения из Java? - PullRequest
258 голосов
/ 25 ноября 2008

Как мне установить переменные окружения из Java? Я вижу, что могу сделать это для подпроцессов, используя ProcessBuilder. Однако мне нужно запустить несколько подпроцессов, поэтому я бы предпочел изменить среду текущего процесса и позволить подпроцессам наследовать ее.

Существует System.getenv(String) для получения одной переменной среды. Я также могу получить Map полного набора переменных окружения с помощью System.getenv(). Но при вызове put() для этого Map выдается UnsupportedOperationException - очевидно, они означают, что среда может быть только для чтения. И нет System.setenv().

Итак, есть ли способ установить переменные среды в текущем запущенном процессе? Если так, то как? Если нет, в чем смысл? (Это потому, что это Java, и поэтому я не должен делать злых непереносимых устаревших вещей, таких как прикосновение к моей среде?) И если нет, то любые полезные предложения по управлению изменениями переменных среды, которые мне нужно будет передать нескольким подпроцессы

Ответы [ 14 ]

3 голосов
/ 25 ноября 2008

Бродя по интернету, похоже, что это возможно сделать с JNI. Затем вам нужно будет вызвать функцию putenv () из C, и вам (предположительно) придется сделать это так, чтобы это работало как в Windows, так и в UNIX.

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

Друг на другом языке, говорящий на Perl, полагает, что это потому, что переменные среды являются глобальными процессами, а Java стремится к хорошей изоляции для хорошего дизайна.

0 голосов
/ 27 апреля 2019

Это злая версия Kotlin @ pushy's evil answer =)

@Suppress("UNCHECKED_CAST")
@Throws(Exception::class)
fun setEnv(newenv: Map<String, String>) {
    try {
        val processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment")
        val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
        theEnvironmentField.isAccessible = true
        val env = theEnvironmentField.get(null) as MutableMap<String, String>
        env.putAll(newenv)
        val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
        theCaseInsensitiveEnvironmentField.isAccessible = true
        val cienv = theCaseInsensitiveEnvironmentField.get(null) as MutableMap<String, String>
        cienv.putAll(newenv)
    } catch (e: NoSuchFieldException) {
        val classes = Collections::class.java.getDeclaredClasses()
        val env = System.getenv()
        for (cl in classes) {
            if ("java.util.Collections\$UnmodifiableMap" == cl.getName()) {
                val field = cl.getDeclaredField("m")
                field.setAccessible(true)
                val obj = field.get(env)
                val map = obj as MutableMap<String, String>
                map.clear()
                map.putAll(newenv)
            }
        }
    }

Работает как минимум в macOS Mojave.

0 голосов
/ 04 июля 2018

Реализация Kotlin, которую я недавно сделал, основываясь на ответе Эдварда:

fun setEnv(newEnv: Map<String, String>) {
    val unmodifiableMapClass = Collections.unmodifiableMap<Any, Any>(mapOf()).javaClass
    with(unmodifiableMapClass.getDeclaredField("m")) {
        isAccessible = true
        @Suppress("UNCHECKED_CAST")
        get(System.getenv()) as MutableMap<String, String>
    }.apply {
        clear()
        putAll(newEnv)
    }
}
0 голосов
/ 25 ноября 2008

Вы можете передать параметры в исходный процесс Java с помощью -D:

java -cp <classpath> -Dkey1=value -Dkey2=value ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...