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?

8voto

Ashley Frieze Punkte 4361

Es gibt drei Bibliotheken, die dies während der Unit-Tests tun können.

Es gibt Stefan Birkners System Rules und System Lambda - https://www.baeldung.com/java-system-rules-junit die es Ihnen ermöglichen, etwas zu tun wie:

public class JUnitTest {

    @Rule
    public EnvironmentVariables environmentVariables = new EnvironmentVariables();

    @Test
    public void someTest() {
        environmentVariables.set("SOME_VARIABLE", "myValue");

        // now System.getenv does what you want
    }
}

oder für System-Lambda:

@Test
void execute_code_with_environment_variables(
) throws Exception {
  List<String> values = withEnvironmentVariable("first", "first value")
    .and("second", "second value")
    .execute(() -> asList(
      System.getenv("first"),
      System.getenv("second")
    ));
  assertEquals(
    asList("first value", "second value"),
    values
  );
}

Die oben genannten Funktionen sind auch als JUnit 5-Erweiterung über System Stubs verfügbar:

@ExtendWith(SystemStubsExtension.class)
class SomeTest {

    @SystemStub
    private EnvironmentVariables;

    @Test
    void theTest() {
        environmentVariables.set("SOME_VARIABLE", "myValue");

        // now System.getenv does what you want

    }

}

System Stubs ist abwärtskompatibel mit System Lambda und System Rules, unterstützt aber JUnit 5.

Alternativ dazu gibt es auch JUnit Pioneer - https://github.com/junit-pioneer/junit-pioneer die es ermöglicht, dass Umgebungsvariablen zur Testzeit über Anmerkungen gesetzt werden können.

8voto

deddu Punkte 757

Wenn Sie wie ich mit diesem Problem beim Testen konfrontiert sind und Junit5 verwenden, Junit-Pionier ist mit sehr hilfreichen Kommentaren versehen. Maven-Freigabe

Beispiel:

@Test
@SetEnvironmentVariable(key = "some variable",value = "new value")
void test() {
    assertThat(System.getenv("some variable")).
        isEqualTo("new value");
}

kann es nicht genug empfehlen.

5voto

skiphoppy Punkte 89474

Poking rund um online, es sieht aus wie es möglich sein könnte, dies mit JNI zu tun. Sie müssten dann einen Aufruf von putenv() von C aus machen, und Sie müssten es (vermutlich) auf eine Weise tun, die sowohl unter Windows als auch unter UNIX funktioniert.

Wenn all das möglich ist, wäre es sicher nicht allzu schwer für Java selbst, dies zu unterstützen, anstatt mich in eine Zwangsjacke zu stecken.

Ein Perl-sprechender Freund deutet an anderer Stelle an, dass dies daran liegt, dass Umgebungsvariablen prozessglobal sind und Java eine gute Isolierung für ein gutes Design anstrebt.

4voto

Johan Ansems Punkte 21

Das Setzen der Umgebungsvariablen im aktuellen Java-Prozess, der nativen Code (eine DLL) verwendet, der auf die betreffende Umgebungsvariable angewiesen ist, funktioniert nur, wenn Sie diese Umgebungsvariable nativ setzen.

Die meisten der Beispiele hier ändern Sie die Karten in der JVM, aber wird nicht funktionieren nativen.

Eine Möglichkeit, die ich gesehen habe, ist über JNI, was wahrscheinlich auch funktioniert. Ein anderer Weg ist die Verwendung von JNA-Plattform durch die Verwendung der Kernel32 Schnittstelle (nur Windows) Zum Beispiel:

private static void setEnv(String key, String value) {
    if(isWindows()) {
        if (!Kernel32.INSTANCE.SetEnvironmentVariable(key, value)) {
            System.err.println("Unable to set the environemnt variable: " + key);
        }
    }
}

Bei einem unix-ähnlichen Betriebssystem ist die LibCAPI Schnittstelle verwendet werden kann, aber ich habe das nicht ausprobiert.

3voto

geosmart Punkte 370

Einfach reflect verwenden, wie setEnv("k1","v1")

    private void setEnv(String key, String val) throws Exception {
        getModifiableEnv().put(key, val);
    }

    private Map<String, String> getModifiableEnv() throws Exception {
        Map<String, String> unmodifiableEnv = System.getenv();
        Field field = unmodifiableEnv.getClass().getDeclaredField("m");
        field.setAccessible(true);
        return (Map<String, String>) field.get(unmodifiableEnv);
    }

brauchen

import java.lang.reflect.Field;
import java.util.Map;

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