409 Stimmen

Wie kann ich in Java Umgebungsvariablen setzen?

Wie kann ich in Java Umgebungsvariablen setzen? Ich sehe, dass ich dies für Unterprozesse tun kann, indem ich ProcessBuilder . Da ich jedoch mehrere Unterprozesse starten muss, würde ich lieber die Umgebung des aktuellen Prozesses ändern und sie an die Unterprozesse weitergeben.

Es gibt eine System.getenv(String) um eine einzelne Umgebungsvariable zu erhalten. Ich kann auch eine Map des vollständigen Satzes von Umgebungsvariablen mit System.getenv() . Aber der Aufruf put() dazu Map wirft einen UnsupportedOperationException -- Sie wollen offenbar, dass die Umgebung nur gelesen werden kann. Und, es gibt keine System.setenv() .

Gibt es also eine Möglichkeit, Umgebungsvariablen im aktuell laufenden Prozess zu setzen? Wenn ja, wie? Wenn nicht, was ist der Grund dafür? (Liegt es daran, dass dies Java ist und ich deshalb keine bösen, nicht portierbaren, veralteten Dinge tun sollte, wie z.B. meine Umgebung anfassen?) Und wenn nicht, gibt es irgendwelche guten Vorschläge für die Verwaltung von Umgebungsvariablenänderungen, die ich an mehrere Unterprozesse weitergeben muss?

2voto

mike rodent Punkte 12041

Die Antwort von Tim Ryan hat bei mir funktioniert... aber ich wollte sie für Groovy (z.B. Spock-Kontext) und simplissimo:

import java.lang.reflect.Field

def getModifiableEnvironmentMap() {
    def unmodifiableEnv = System.getenv()
    Class cl = unmodifiableEnv.getClass()
    Field field = cl.getDeclaredField("m")
    field.accessible = true
    field.get(unmodifiableEnv)
}

def clearEnvironmentVars( def keys ) {
    def savedVals = [:]
    keys.each{ key ->
        String val = modifiableEnvironmentMap.remove(key)
        // thinking about it, I'm not sure why we need this test for null
        // but haven't yet done any experiments
        if( val != null ) {
            savedVals.put( key, val )
        }
    }
    savedVals
}

def setEnvironmentVars(Map varMap) {
    modifiableEnvironmentMap.putAll(varMap)
}

// pretend existing Env Var doesn't exist
def PATHVal1 = System.env.PATH
println "PATH val1 |$PATHVal1|"
String[] keys = ["PATH", "key2", "key3"]
def savedVars = clearEnvironmentVars(keys)
def PATHVal2 = System.env.PATH
println "PATH val2 |$PATHVal2|"

// return to reality
setEnvironmentVars(savedVars)
def PATHVal3 = System.env.PATH
println "PATH val3 |$PATHVal3|"
println "System.env |$System.env|"

// pretend a non-existent Env Var exists
setEnvironmentVars( [ 'key4' : 'key4Val' ])
println "key4 val |$System.env.key4|"

2voto

Arun Sharma Punkte 21

Ich bin über diesen Thread gestolpert, da ich eine ähnliche Anforderung hatte, bei der ich eine Umgebungsvariable (dauerhaft) festlegen (oder aktualisieren) musste.

Also habe ich nachgeschaut - wie man eine Umgebungsvariable dauerhaft von der Eingabeaufforderung aus setzt und es war sehr einfach!

setx JAVA_LOC C:/Java/JDK

Dann habe ich einfach das Gleiche in meinem Code implementiert Ich habe folgendes verwendet (angenommen - JAVA_LOC ist der Name der Umgebungsvariablen)

        String cmdCommand = "setx JAVA_LOC " + "C:/Java/JDK";
            ProcessBuilder processBuilder = new ProcessBuilder();
            processBuilder.command("cmd.exe", "/c", cmdCommand);
            processBuilder.start();

ProcessBuilder ruft eine cmd.exe auf und übergibt den gewünschten Befehl. Die Umgebungsvariable wird beibehalten, auch wenn Sie die JVM beenden/den Rechner neu starten, da sie keinen Bezug zum Lebenszyklus der JVM/des Programms hat.

1voto

GarouDan Punkte 3509

Dies ist die böse Kotlin-Version des bösen @pushy's Antwort \=)

@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)
            }
        }
    }

Zumindest in macOS Mojave funktioniert es.

0voto

Tiarê Balbi Punkte 1361

Eine Version in Kotlin, in diesem Algorithmus habe ich einen Dekorator erstellt, mit dem man Variablen aus der Umgebung setzen und abrufen kann.

import java.util.Collections
import kotlin.reflect.KProperty

class EnvironmentDelegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return System.getenv(property.name) ?: "-"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        val key = property.name

        val classes: Array<Class<*>> = Collections::class.java.declaredClasses
        val env = System.getenv()

        val cl = classes.first { "java.util.Collections\$UnmodifiableMap" == it.name }

        val field = cl.getDeclaredField("m")
        field.isAccessible = true
        val obj = field[env]
        val map = obj as MutableMap<String, String>
        map.putAll(mapOf(key to value))
    }
}

class KnownProperties {
    var JAVA_HOME: String by EnvironmentDelegate()
    var sample: String by EnvironmentDelegate()
}

fun main() {
    val knowProps = KnownProperties()
    knowProps.sample = "2"

    println("Java Home: ${knowProps.JAVA_HOME}")
    println("Sample: ${knowProps.sample}")
}

-1voto

Keith K Punkte 1

jython Variante basierend auf @pushy's Antwort, funktioniert unter Windows.

def set_env(newenv):
    from java.lang import Class
    process_environment = Class.forName("java.lang.ProcessEnvironment")
    environment_field =  process_environment.getDeclaredField("theEnvironment")
    environment_field.setAccessible(True)
    env = environment_field.get(None)
    env.putAll(newenv)
    invariant_environment_field = process_environment.getDeclaredField("theCaseInsensitiveEnvironment");
    invariant_environment_field.setAccessible(True)
    invevn = invariant_environment_field.get(None)
    invevn.putAll(newenv)

使用することです:

old_environ = dict(os.environ)
old_environ['EPM_ORACLE_HOME'] = r"E:\Oracle\Middleware\EPMSystem11R1"
set_env(old_environ)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X