Frage

Wie kann ich Umgebungsvariablen aus Java? Ich sehe, dass ich dies für Teilprozesse tun kann mit ProcessBuilder . Ich habe mehrere Teilprozesse zu starten, obwohl, so würde ich eher den aktuellen Prozess Umgebung ändern und lassen Sie die Subprozesse es erben.

Es gibt eine System.getenv(String) für eine einzige Umgebungsvariable zu bekommen. Ich kann auch eine Map des vollständigen Satzes von Umgebungsvariablen mit System.getenv() erhalten. Aber an diesem put() Map Aufruf wirft einen UnsupportedOperationException - anscheinend bedeuten sie für die Umwelt nur zu lesen. Und es gibt keinen System.setenv().

So ist es eine Möglichkeit, Umgebungsvariablen im laufenden Prozess zu setzen? Wenn das so ist, wie? Wenn nicht, was ist der Grund? (Ist es, weil diese Java ist und deshalb soll ich nicht meine Umgebung wie zu berühren, Böse zu tun nonportable veraltete Dinge sein?) Und wenn nicht, gute Vorschläge für die Verwaltung der Umgebungsvariable ändert, dass ich gehen zu müssen, um mehr zu füttern Subprozesse?

War es hilfreich?

Lösung

  

(Ist es, weil diese Java ist und deshalb sollte ich nicht meine Umgebung wie zu berühren, Böses zu tun nonportable veraltete Dinge werden?)

Ich glaube, Sie den Nagel auf den Kopf getroffen haben.

Ein möglicher Weg, um die Last zu erleichtern würde, ein Verfahren zur ausklammern

void setUpEnvironment(ProcessBuilder builder) {
    Map<String, String> env = builder.environment();
    // blah blah
}

und übergeben alle ProcessBuilders durch bevor sie beginnen.

Auch Sie wahrscheinlich bereits wissen, aber Sie können mit dem gleichen ProcessBuilder mehr als einen Prozess starten. Also, wenn Ihr Subprozesse die gleichen sind, die Sie nicht brauchen diese Einstellung über und über zu tun.

Andere Tipps

Für den Einsatz in Szenarien, in denen Sie bestimmte Umgebungswerte für Unit-Tests festlegen müssen, können Sie den folgenden Hack nützlich finden. Es wird die Umgebungsvariablen in der gesamten JVM ändern (so stellen Sie sicher, dass Sie alle Änderungen nach dem Test Reset), wird aber nicht Ihre Systemumgebung verändern.

Ich fand, dass eine Kombination der beiden schmutzigen Hacks von Edward Campbell und anonym am besten funktioniert, als einer der nicht unter Linux funktioniert, muss man nicht 7 unter Windows arbeiten, so ein Multi-Plattform bösen Hack, den ich ihnen kombiniert zu bekommen:

protected static void setEnv(Map<String, String> newenv) throws Exception {
  try {
    Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
    Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
    theEnvironmentField.setAccessible(true);
    Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
    env.putAll(newenv);
    Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
    theCaseInsensitiveEnvironmentField.setAccessible(true);
    Map<String, String> cienv = (Map<String, String>)     theCaseInsensitiveEnvironmentField.get(null);
    cienv.putAll(newenv);
  } catch (NoSuchFieldException e) {
    Class[] classes = Collections.class.getDeclaredClasses();
    Map<String, String> env = System.getenv();
    for(Class cl : classes) {
      if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
        Field field = cl.getDeclaredField("m");
        field.setAccessible(true);
        Object obj = field.get(env);
        Map<String, String> map = (Map<String, String>) obj;
        map.clear();
        map.putAll(newenv);
      }
    }
  }
}

Dies funktioniert wie ein Zauber. Voll Kredite an den beiden Autoren dieser Hacks.

public static void set(Map<String, String> newenv) throws Exception {
    Class[] classes = Collections.class.getDeclaredClasses();
    Map<String, String> env = System.getenv();
    for(Class cl : classes) {
        if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
            Field field = cl.getDeclaredField("m");
            field.setAccessible(true);
            Object obj = field.get(env);
            Map<String, String> map = (Map<String, String>) obj;
            map.clear();
            map.putAll(newenv);
        }
    }
}

oder hinzuzufügen / Aktualisieren eines einzelnen var und Entfernen der Schleife gemäß thejoshwolfe Vorschlag.

@SuppressWarnings({ "unchecked" })
  public static void updateEnv(String name, String val) throws ReflectiveOperationException {
    Map<String, String> env = System.getenv();
    Field field = env.getClass().getDeclaredField("m");
    field.setAccessible(true);
    ((Map<String, String>) field.get(env)).put(name, val);
  }
// this is a dirty hack - but should be ok for a unittest.
private void setNewEnvironmentHack(Map<String, String> newenv) throws Exception
{
  Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
  Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
  theEnvironmentField.setAccessible(true);
  Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
  env.clear();
  env.putAll(newenv);
  Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
  theCaseInsensitiveEnvironmentField.setAccessible(true);
  Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
  cienv.clear();
  cienv.putAll(newenv);
}

auf Android die Schnittstelle über Libcore.os als eine Art versteckter API ausgesetzt ist.

Libcore.os.setenv("VAR", "value", bOverwrite);
Libcore.os.getenv("VAR"));

Die libcore Klasse sowie die Schnittstelle OS ist öffentlich. Nur die Klassendeklaration fehlt und müssen an den Linker zu zeigen. Keine Notwendigkeit, die Klassen der Anwendung hinzuzufügen, aber es ist auch nicht schaden, wenn es enthalten ist.

package libcore.io;

public final class Libcore {
    private Libcore() { }

    public static Os os;
}

package libcore.io;

public interface Os {
    public String getenv(String name);
    public void setenv(String name, String value, boolean overwrite) throws ErrnoException;
}

Linux nur

Einstellen einzelne Umgebungsvariablen (basierend auf Antwort von Edward Campbell):

public static void setEnv(String key, String value) {
    try {
        Map<String, String> env = System.getenv();
        Class<?> cl = env.getClass();
        Field field = cl.getDeclaredField("m");
        field.setAccessible(true);
        Map<String, String> writableEnv = (Map<String, String>) field.get(env);
        writableEnv.put(key, value);
    } catch (Exception e) {
        throw new IllegalStateException("Failed to set environment variable", e);
    }
}

Verwendung:

Zuerst legen Sie die Methode in jeder Klasse, die Sie wollen, zum Beispiel SystemUtil.

SystemUtil.setEnv("SHELL", "/bin/bash");

Wenn Sie System.getenv("SHELL") nach diesem Aufruf, werden Sie "/bin/bash" zurück.

Es stellt sich heraus, dass die Lösung von @ aufdringlich / @ anonym / @ Edward Campbell auf Android funktioniert nicht, weil Android nicht wirklich Java ist. Insbesondere hat Android nicht java.lang.ProcessEnvironment überhaupt. Aber es stellt sich heraus, in Android einfacher zu sein, brauchen Sie nur einen JNI Aufruf POSIX setenv() zu tun:

In C / JNI:

JNIEXPORT jint JNICALL Java_com_example_posixtest_Posix_setenv
  (JNIEnv* env, jclass clazz, jstring key, jstring value, jboolean overwrite)
{
    char* k = (char *) (*env)->GetStringUTFChars(env, key, NULL);
    char* v = (char *) (*env)->GetStringUTFChars(env, value, NULL);
    int err = setenv(k, v, overwrite);
    (*env)->ReleaseStringUTFChars(env, key, k);
    (*env)->ReleaseStringUTFChars(env, value, v);
    return err;
}

Und in Java:

public class Posix {

    public static native int setenv(String key, String value, boolean overwrite);

    private void runTest() {
        Posix.setenv("LD_LIBRARY_PATH", "foo", true);
    }
}

Dies ist eine Kombination von @ paul-blair s-Code ‚s Antwort auf Java umgewandelt, die einige Bereinigungen, die in @pushy gewesen zu sein scheinen darauf hingewiesen, von Paul Blair und einige Fehler enthält‘, die aus @Edward Campbell gemacht wird und anonym.

Ich kann gar nicht genug betonen, wie sehr dieser Code nur in Tests verwendet werden soll, und ist extrem Hacky. Aber für Fälle, in denen Sie die Umgebung Setup in Tests müssen es ist genau das, was ich brauchte.

Dazu gehören auch einige kleinere Berührungen von mir, dass der Code erlauben sowohl unter Windows läuft auf

zu arbeiten
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

sowie Centos läuft auf

openjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)

Die Umsetzung:

/**
 * Sets an environment variable FOR THE CURRENT RUN OF THE JVM
 * Does not actually modify the system's environment variables,
 *  but rather only the copy of the variables that java has taken,
 *  and hence should only be used for testing purposes!
 * @param key The Name of the variable to set
 * @param value The value of the variable to set
 */
@SuppressWarnings("unchecked")
public static <K,V> void setenv(final String key, final String value) {
    try {
        /// we obtain the actual environment
        final Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
        final Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
        final boolean environmentAccessibility = theEnvironmentField.isAccessible();
        theEnvironmentField.setAccessible(true);

        final Map<K,V> env = (Map<K, V>) theEnvironmentField.get(null);

        if (SystemUtils.IS_OS_WINDOWS) {
            // This is all that is needed on windows running java jdk 1.8.0_92
            if (value == null) {
                env.remove(key);
            } else {
                env.put((K) key, (V) value);
            }
        } else {
            // This is triggered to work on openjdk 1.8.0_91
            // The ProcessEnvironment$Variable is the key of the map
            final Class<K> variableClass = (Class<K>) Class.forName("java.lang.ProcessEnvironment$Variable");
            final Method convertToVariable = variableClass.getMethod("valueOf", String.class);
            final boolean conversionVariableAccessibility = convertToVariable.isAccessible();
            convertToVariable.setAccessible(true);

            // The ProcessEnvironment$Value is the value fo the map
            final Class<V> valueClass = (Class<V>) Class.forName("java.lang.ProcessEnvironment$Value");
            final Method convertToValue = valueClass.getMethod("valueOf", String.class);
            final boolean conversionValueAccessibility = convertToValue.isAccessible();
            convertToValue.setAccessible(true);

            if (value == null) {
                env.remove(convertToVariable.invoke(null, key));
            } else {
                // we place the new value inside the map after conversion so as to
                // avoid class cast exceptions when rerunning this code
                env.put((K) convertToVariable.invoke(null, key), (V) convertToValue.invoke(null, value));

                // reset accessibility to what they were
                convertToValue.setAccessible(conversionValueAccessibility);
                convertToVariable.setAccessible(conversionVariableAccessibility);
            }
        }
        // reset environment accessibility
        theEnvironmentField.setAccessible(environmentAccessibility);

        // we apply the same to the case insensitive environment
        final Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
        final boolean insensitiveAccessibility = theCaseInsensitiveEnvironmentField.isAccessible();
        theCaseInsensitiveEnvironmentField.setAccessible(true);
        // Not entirely sure if this needs to be casted to ProcessEnvironment$Variable and $Value as well
        final Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
        if (value == null) {
            // remove if null
            cienv.remove(key);
        } else {
            cienv.put(key, value);
        }
        theCaseInsensitiveEnvironmentField.setAccessible(insensitiveAccessibility);
    } catch (final ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
        throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+">", e);
    } catch (final NoSuchFieldException e) {
        // we could not find theEnvironment
        final Map<String, String> env = System.getenv();
        Stream.of(Collections.class.getDeclaredClasses())
                // obtain the declared classes of type $UnmodifiableMap
                .filter(c1 -> "java.util.Collections$UnmodifiableMap".equals(c1.getName()))
                .map(c1 -> {
                    try {
                        return c1.getDeclaredField("m");
                    } catch (final NoSuchFieldException e1) {
                        throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+"> when locating in-class memory map of environment", e1);
                    }
                })
                .forEach(field -> {
                    try {
                        final boolean fieldAccessibility = field.isAccessible();
                        field.setAccessible(true);
                        // we obtain the environment
                        final Map<String, String> map = (Map<String, String>) field.get(env);
                        if (value == null) {
                            // remove if null
                            map.remove(key);
                        } else {
                            map.put(key, value);
                        }
                        // reset accessibility
                        field.setAccessible(fieldAccessibility);
                    } catch (final ConcurrentModificationException e1) {
                        // This may happen if we keep backups of the environment before calling this method
                        // as the map that we kept as a backup may be picked up inside this block.
                        // So we simply skip this attempt and continue adjusting the other maps
                        // To avoid this one should always keep individual keys/value backups not the entire map
                        LOGGER.info("Attempted to modify source map: "+field.getDeclaringClass()+"#"+field.getName(), e1);
                    } catch (final IllegalAccessException e1) {
                        throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+">. Unable to access field!", e1);
                    }
                });
    }
    LOGGER.info("Set environment variable <"+key+"> to <"+value+">. Sanity Check: "+System.getenv(key));
}

Stochern online, es sieht aus wie es möglich sein könnte, dies mit JNI zu tun. Sie würden dann einen Anruf tätigen müssen, um putenv () von C, und Sie würden (vermutlich) haben es in einer Art und Weise zu tun, die auf Windows und UNIX gearbeitet.

Wenn alles, was getan werden kann, wäre es sicherlich nicht zu hart sein für Java selbst, dies zu unterstützen, anstatt mich in einer Zwangsjacke zu stellen.

Ein Perl-sprechender Freund schlägt vor, an anderer Stelle, dass dies, weil Umgebungsvariablen Prozess global ist und Java ist für eine gute Isolierung für gutes Design streben.

Versuchte aufdringlich Antwort oben und es zum größten Teil gearbeitet. Jedoch unter bestimmten Umständen, ich würde diese Ausnahme sehen:

java.lang.String cannot be cast to java.lang.ProcessEnvironment$Variable

Dies stellt sich heraus zu geschehen, wenn das Verfahren mehr als einmal aufgerufen wurde, um die Durchführung bestimmter innerer Klassen von ProcessEnvironment. aufgrund Wenn die setEnv(..) Methode mehr als einmal aufgerufen wird, wenn die Schlüssel aus der theEnvironment Karte abgerufen werden, sind sie jetzt Strings (nachdem durch den ersten Aufruf von setEnv(...) setzte in als Strings worden ist) und nicht auf die Karte der generischen Typen umgewandelt werden kann, Variable,, die eine private innere Klasse von ProcessEnvironment. ist

Eine feste Version (in Scala), ist unten. Hoffentlich ist es nicht zu schwierig ist, in Java zu übertragen.

def setEnv(newenv: java.util.Map[String, String]): Unit = {
  try {
    val processEnvironmentClass = JavaClass.forName("java.lang.ProcessEnvironment")
    val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
    theEnvironmentField.setAccessible(true)

    val variableClass = JavaClass.forName("java.lang.ProcessEnvironment$Variable")
    val convertToVariable = variableClass.getMethod("valueOf", classOf[java.lang.String])
    convertToVariable.setAccessible(true)

    val valueClass = JavaClass.forName("java.lang.ProcessEnvironment$Value")
    val convertToValue = valueClass.getMethod("valueOf", classOf[java.lang.String])
    convertToValue.setAccessible(true)

    val sampleVariable = convertToVariable.invoke(null, "")
    val sampleValue = convertToValue.invoke(null, "")
    val env = theEnvironmentField.get(null).asInstanceOf[java.util.Map[sampleVariable.type, sampleValue.type]]
    newenv.foreach { case (k, v) => {
        val variable = convertToVariable.invoke(null, k).asInstanceOf[sampleVariable.type]
        val value = convertToValue.invoke(null, v).asInstanceOf[sampleValue.type]
        env.put(variable, value)
      }
    }

    val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
    theCaseInsensitiveEnvironmentField.setAccessible(true)
    val cienv = theCaseInsensitiveEnvironmentField.get(null).asInstanceOf[java.util.Map[String, String]]
    cienv.putAll(newenv);
  }
  catch {
    case e : NoSuchFieldException => {
      try {
        val classes = classOf[java.util.Collections].getDeclaredClasses
        val env = System.getenv()
        classes foreach (cl => {
          if("java.util.Collections$UnmodifiableMap" == cl.getName) {
            val field = cl.getDeclaredField("m")
            field.setAccessible(true)
            val map = field.get(env).asInstanceOf[java.util.Map[String, String]]
            // map.clear() // Not sure why this was in the code. It means we need to set all required environment variables.
            map.putAll(newenv)
          }
        })
      } catch {
        case e2: Exception => e2.printStackTrace()
      }
    }
    case e1: Exception => e1.printStackTrace()
  }
}

Wie die meisten Menschen, die diesen Thread gefunden haben, war ich einige Unit-Tests und benötigt das Schreiben der Umgebungsvariablen zu ändern, um die richtigen Bedingungen für den Test einstellen zu laufen. Allerdings fand ich die meisten upvoted Antworten hatten einige Probleme und / oder waren sehr kryptisch oder zu kompliziert. Hoffentlich wird dies anderen helfen, die Lösung schneller zu sortieren.

Zunächst einmal, fand ich endlich @Hubert Grzeskowiak Lösung die einfachste zu sein, und es funktionierte für mich. Ich wünschte, ich würde zuerst zu, dass man gekommen ist. Es basiert auf @Edward Campbell Antwort, aber ohne erschwerende für Schleife Suche.

Allerdings begann ich mit @ aufdringlich-Lösung, die die meisten upvotes bekam. Es ist eine Kombination aus @anonymous und @Edward Campbell. @pushy Ansprüche sind beide Ansätze benötigt sowohl Linux als auch Windows-Umgebungen abzudecken. Ich bin unter OS X laufen und feststellen, dass beide arbeiten (einmal ein Problem mit @anonymous Ansatz festgelegt ist). Wie andere bereits erwähnt haben, funktioniert diese Lösung die meiste Zeit, aber nicht alle.

Ich denke, die Quelle der meisten der Verwirrung von @ anonymouss Lösung kommt auf die ‚theEnvironment‘ Feld arbeitet. Mit Blick auf die Definition der ProcessEnvironment Struktur, 'theEnvironment' ist keine Map , sondern es ist eine Karte . die Karte Löschen funktioniert gut, aber die putAll Betrieb baut die Karte eine Karte , die möglicherweise Probleme verursacht, wenn nachfolgende Operationen auf die Datenstruktur unter Verwendung der normalen API arbeiten, die Karte erwartet. Auch den Zugriff auf / Entfernen einzelner Elemente ist ein Problem. Die Lösung ist ‚theEnvironment‘ indirekt über ‚theUnmodifiableEnvironment‘ zuzugreifen. Aber da es sich um eine Art UnmodifiableMap der Zugang muss der UnmodifiableMap Typ durch die private Variable 'm' erfolgen. Siehe getModifiableEnvironmentMap2 in Code unten.

In meinem Fall musste ich einige der Umgebungsvariablen für meinen Test entfernen (die anderen sollten unverändert). Dann wollte ich die Umgebungsvariablen in ihren vorherigen Zustand nach dem Test wieder herzustellen. Die Routinen unten machen, dass gerade nach vorne zu tun. Getestet habe ich beide Versionen von getModifiableEnvironmentMap auf OS X, und beide arbeiten äquivalent. Obwohl auf Kommentare in diesem Thread basiert, kann man eine bessere Wahl sein als die anderen abhängig von der Umgebung.

. Hinweis: Ich habe keinen Zugriff auf die ‚theCaseInsensitiveEnvironmentField‘ einzubeziehen, sofern diese Windows-spezifisch zu sein scheint, und ich hatte keine Möglichkeit, es zu testen, aber das Hinzufügen es sollte einfach sein

private Map<String, String> getModifiableEnvironmentMap() {
    try {
        Map<String,String> unmodifiableEnv = System.getenv();
        Class<?> cl = unmodifiableEnv.getClass();
        Field field = cl.getDeclaredField("m");
        field.setAccessible(true);
        Map<String,String> modifiableEnv = (Map<String,String>) field.get(unmodifiableEnv);
        return modifiableEnv;
    } catch(Exception e) {
        throw new RuntimeException("Unable to access writable environment variable map.");
    }
}

private Map<String, String> getModifiableEnvironmentMap2() {
    try {
        Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
        Field theUnmodifiableEnvironmentField = processEnvironmentClass.getDeclaredField("theUnmodifiableEnvironment");
        theUnmodifiableEnvironmentField.setAccessible(true);
        Map<String,String> theUnmodifiableEnvironment = (Map<String,String>)theUnmodifiableEnvironmentField.get(null);

        Class<?> theUnmodifiableEnvironmentClass = theUnmodifiableEnvironment.getClass();
        Field theModifiableEnvField = theUnmodifiableEnvironmentClass.getDeclaredField("m");
        theModifiableEnvField.setAccessible(true);
        Map<String,String> modifiableEnv = (Map<String,String>) theModifiableEnvField.get(theUnmodifiableEnvironment);
        return modifiableEnv;
    } catch(Exception e) {
        throw new RuntimeException("Unable to access writable environment variable map.");
    }
}

private Map<String, String> clearEnvironmentVars(String[] keys) {

    Map<String,String> modifiableEnv = getModifiableEnvironmentMap();

    HashMap<String, String> savedVals = new HashMap<String, String>();

    for(String k : keys) {
        String val = modifiableEnv.remove(k);
        if (val != null) { savedVals.put(k, val); }
    }
    return savedVals;
}

private void setEnvironmentVars(Map<String, String> varMap) {
    getModifiableEnvironmentMap().putAll(varMap);   
}

@Test
public void myTest() {
    String[] keys = { "key1", "key2", "key3" };
    Map<String, String> savedVars = clearEnvironmentVars(keys);

    // do test

    setEnvironmentVars(savedVars);
}

Dies ist die Kotlin böse Version des bösen beantworten =)

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

Es ist in macOS Mojave zumindest arbeiten.

Kotlin Umsetzung Ich habe kürzlich basierend auf Edwards Antwort:

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

Sie können Ihren ersten Java-Prozess übergeben Parameter in mit -D:

java -cp <classpath> -Dkey1=value -Dkey2=value ...
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top