سؤال

كيف يمكنني تعيين متغيرات البيئة من جافا ؟ أرى أنني يمكن أن تفعل هذا من أجل فرعية باستخدام ProcessBuilder.لدي عدة فرعية للبدء, رغم أن, لذلك أنا أفضل أن تعديل العملية الحالية بيئة والسماح فرعية ترث منه.

هناك System.getenv(String) للحصول على واحد متغير البيئة.أنا يمكن أيضا الحصول على Map من مجموعة كاملة من متغيرات البيئة مع System.getenv().ولكن الدعوة put() على أن Map يلقي UnsupportedOperationException -- على ما يبدو أنها تعني البيئة أن يكون للقراءة فقط.و لا يوجد System.setenv().

هل هناك أي طريقة تعيين متغيرات البيئة في حاليا قيد التشغيل ؟ إذا كان الأمر كذلك ، كيف ؟ إن لم يكن, ما الأسباب ؟ (هل لأن هذا هو جافا وبالتالي لا يجب أن أفعل الشر nonportable أشياء عفا عليها الزمن مثل لمس بلدي البيئة؟) و إذا لم يكن كذلك ، أي اقتراحات جيدة لإدارة متغير البيئة التغييرات التي أنا بحاجة إلى أن تكون التغذية إلى عدة فرعية?

هل كانت مفيدة؟

المحلول

(هل لأن هذا هو جافا وبالتالي لا يجب أن أفعل الشر nonportable أشياء عفا عليها الزمن مثل لمس بلدي البيئة؟)

أعتقد أن كنت قد ضرب المسمار على رأسه.

ممكن طريقة لتخفيف العبء سيكون عامل طريقة

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

وتمرير أي ProcessBuilders من خلال ذلك قبل البدء بها.

كما أنه من المحتمل أنك تعرف هذا ، ولكن يمكنك أن تبدأ عملية واحدة أو أكثر مع نفس ProcessBuilder.حتى إذا كان لديك فرعية هي نفسها, لا تحتاج أن تفعل هذا الإعداد أكثر و أكثر.

نصائح أخرى

للاستخدام في الحالات حيث تحتاج إلى تعيين بيئة معينة القيم وحدة الاختبارات ، قد تجد التالية الإختراق مفيدة.فإنه سيتم تغيير متغيرات البيئة في جميع أنحاء JVM (لذلك تأكد من تعيين أي تغييرات بعد الاختبار) ، ولكن لن يغير بيئة النظام الخاص بك.

لقد وجدت أنه مزيج من الاثنين القذرة الخارقة من قبل إدوارد كامبل مجهول يعمل بشكل أفضل ، باعتبارها واحدة من لا يعمل تحت نظام لينكس لا تعمل تحت ويندوز 7.وذلك للحصول على المتعدد الشر هاك أنا منها مجتمعة:

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

هذا يعمل مثل السحر.الاعتمادات كاملة إلى اثنين من المؤلفين من هذه الخارقة.

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

أو إضافة/تحديث واحد فار وإزالة حلقة كما في thejoshwolfe اقتراح.

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

على الروبوت واجهة يتعرض عبر Libcore.نظام التشغيل كنوع من خفية API.

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

على Libcore الطبقة فضلا عن واجهة نظام التشغيل العامة.فقط الطبقة إعلان مفقود ولا تحتاج إلى أن تظهر إلى رابط.لا حاجة لإضافة فئات التطبيق ولكن أيضا لا يضر إذا كان يتم تضمين.

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

لينكس فقط

وضع واحد متغيرات البيئة (على أساس الإجابة من قبل إدوارد كامبل):

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

الاستخدام:

أولا وضع الطريقة في أي فئة تريد, مثلاSystemUtil.

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

إذا كنت استدعاء System.getenv("SHELL") بعد ذلك سوف تحصل على "/bin/bash" مرة أخرى.

اتضح أن الحل من @انتهازي/@المجهول/@إدوارد كامبل لا يعمل على الروبوت لالروبوت ليس جافا.على وجه التحديد, الروبوت لا java.lang.ProcessEnvironment في كل.ولكن اتضح أن تكون أسهل في الروبوت, تحتاج فقط إلى القيام JNI الدعوة إلى POSIX setenv():

في 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;
}

و في جاوة:

public class Posix {

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

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

هذا هو مزيج من @بول-بلير 's الإجابة تحويلها إلى جافا والذي يتضمن بعض تنظيفات أشار بول بلير وبعض الأخطاء التي يبدو أنه قد تم داخل @انتهازي 's رمز التي تتكون من @إدوارد كامبل مجهول.

لا أستطيع أن أؤكد كم هذا الرمز يجب أن يستخدم فقط في اختبار للغاية hacky.ولكن في الحالات التي تحتاج البيئة الإعداد في الاختبارات هو بالضبط ما كنت بحاجة.

وهذا يشمل أيضا بعض اللمسات الطفيفة من الألغام التي تسمح رمز للعمل على كل من ويندوز يعمل على

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)

وكذلك تعمل على Centos

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)

تنفيذ:

/**
 * 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));
}

التلصص على الانترنت يبدو أنه قد يكون من الممكن القيام بذلك مع JNI.ثم كنت قد للاتصال putenv() من ج ، و كنت (يفترض) أن تفعل ذلك في الطريقة التي عملت على كل من ويندوز و يونيكس.

إذا كان كل ما يمكن القيام به ، فإنه بالتأكيد لن يكون من الصعب جدا بالنسبة جافا نفسها لدعم هذا بدلا من وضع لي في سترة على التوالي.

Perl الناطقة صديق في مكان آخر يشير إلى أن هذا هو بسبب متغيرات البيئة هي عملية عالمية جافا تسعى للخير العزلة عن التصميم الجيد.

حاولت انتهازي الجواب أعلاه وعملت معظم الأحيان.ومع ذلك ، في بعض الظروف ، أود أن أرى هذا الاستثناء:

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

تبين أن هذا يحدث عندما تم استدعاء الطريقة أكثر من مرة ، بسبب تنفيذ بعض الطبقات الداخلية من ProcessEnvironment. إذا كان setEnv(..) طريقة دعا أكثر من مرة ، عندما مفاتيح يتم استردادها من theEnvironment خريطة هم الآن السلاسل (بعد أن وضعت في السلاسل الأولى الاحتجاج setEnv(...) ) و لا يمكن أن يلقي على الخريطة نوع عام ، Variable, خاصة الطبقة الداخلية من ProcessEnvironment.

نسخة ثابتة (في سكالا) ، أدناه.نأمل انها ليست من الصعب جدا أن تحمل أكثر في جافا.

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

مثل معظم الناس الذين وجدوا هذا الموضوع ، كنت أكتب بعض اختبارات الوحدة وتحتاج إلى تعديل متغيرات البيئة إلى مجموعة الظروف الصحيحة لاختبار الترشح.ومع ذلك ، وجدت معظم upvoted إجابات بعض القضايا و/أو خفي أو معقدة أكثر من اللازم.نأمل أن هذا سوف يساعد الآخرين على فرز الحل بسرعة أكبر.

أولا وأخيرا وجدت @هوبير Grzeskowiak حل أبسط و عملت بالنسبة لي.أتمنى أن جئت إلى أن أول واحد.إنه على أساس @إدوارد كامبل الإجابة ، ولكن من دون تعقيد لحلقة البحث.

ومع ذلك ، بدأت مع @انتهازي الحل ، التي حصلت على أكثر القطرية.هذا هو التحرير والسرد @مجهول @إدوارد كامبل.@انتهازي يدعي كلا النهجين اللازمة لتغطية كل بيئات Windows و Linux.أنا على التوالي تحت OS X و تجد أن كل عمل (مرة مشكلة مع @مجهول نهج ثابت).كما ذكر آخرون أن هذا الحل يعمل معظم الوقت ، ولكن ليس كلها.

أعتقد أن مصدر معظم الارتباك يأتي من @مجهول حل العاملة في 'البيئة' المجال.تبحث في تعريف ProcessEnvironment الهيكل 'البيئة' ليس خريطة< String, String > بل هو الخريطة< متغير القيمة >.مسح خريطة يعمل بشكل جيد, ولكن putAll عملية بناء الخريطة خريطة< String, String > الذي يحتمل أن يسبب مشاكل عند العمليات اللاحقة تعمل على بنية البيانات باستخدام API الطبيعي أن تتوقع خريطة< متغير القيمة >.أيضا الوصول إلى/إزالة العناصر الفردية هو المشكلة.الحل هو الوصول 'البيئة' بشكل غير مباشر من خلال 'theUnmodifiableEnvironment'.ولكن لأن هذا هو نوع UnmodifiableMap الوصول يجب أن يتم من خلال القطاع الخاص متغير 'm' من UnmodifiableMap نوع.انظر getModifiableEnvironmentMap2 في البرمجية أدناه.

في حالتي أنا في حاجة إلى إزالة بعض متغيرات البيئة أجل اختبار (الآخرين يجب أن يكون دون تغيير).ثم أردت أن استعادة متغيرات البيئة إلى ما قبل الدولة بعد الاختبار.إجراءات أدناه جعل هذا مستقيم إلى الأمام للقيام.أنا اختبرت كلا الإصدارين من getModifiableEnvironmentMap على OS X ، والعمل على حد سواء مكافئ.على الرغم استنادا إلى التعليقات في هذا الموضوع, قد يكون خيارا أفضل من الآخر اعتمادا على البيئة.

ملاحظة:لم تشمل الوصول إلى 'theCaseInsensitiveEnvironmentField' حيث يبدو أن ويندوز محددة وليس لدي أي وسيلة لاختبار ذلك ، ولكن مضيفا أنه ينبغي على التوالي إلى الأمام.

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

هذا هو Kotlin الشر الإصدار من @انتهازي الشر الجواب =)

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

وهي تعمل في ماك موهافي على الأقل.

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

يمكنك تمرير المعلمات إلى الأولي الخاص بك جافا العملية -D:

java -cp <classpath> -Dkey1=value -Dkey2=value ...
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top