Как и большинство людей, которые нашли этот поток, я писал некоторые модульные тесты, и мне нужно было изменить переменные среды, чтобы установить правильные условия для выполнения теста. Тем не менее, я обнаружил, что ответы с наибольшим количеством голосов имели некоторые проблемы и / или были очень загадочными или чрезмерно сложными. Надеюсь, это поможет другим быстрее разобраться в решении.
Во-первых, я наконец нашел решение @Hubert Grzeskowiak самым простым, и оно сработало для меня. Я хотел бы прийти к этому первым. Это основано на ответе Эдварда Кэмпбелла, но без усложнения циклического поиска.
Однако я начал с решения @ pushy, которое получило наибольшее количество голосов. Это комбинация @anonymous и @Edward Campbell's. @pushy утверждает, что оба подхода необходимы для охвата как среды Linux, так и Windows. Я работаю под OS X и обнаружил, что оба работают (как только проблема с подходом @anonymous решена). Как уже отмечали другие, это решение работает большую часть времени, но не все.
Я думаю, что источником большей части путаницы является решение @ anonymous, работающее в области «TheEnvironment». Глядя на определение структуры ProcessEnvironment , «theEnvironment» - это не карта <String, String>, а карта <переменная, значение>. Очистка карты работает нормально, но операция putAll перестраивает карту Map <String, String>, что потенциально вызывает проблемы, когда последующие операции работают с структурой данных с использованием обычного API, который ожидает Map <Variable, Value>. Кроме того, доступ / удаление отдельных элементов является проблемой. Решение состоит в том, чтобы получить доступ к «Среде» косвенно через «Немодифицируемую Среду». Но так как это тип UnmodifiableMapдоступ должен быть сделан через закрытую переменную 'm' типа UnmodifiableMap. Смотрите getModifiableEnvironmentMap2 в коде ниже.
В моем случае мне нужно было удалить некоторые переменные окружения для моего теста (остальные должны быть неизменными). Затем я хотел восстановить переменные среды до их прежнего состояния после теста. Процедуры ниже делают это прямо вперед, чтобы сделать. Я протестировал обе версии getModifiableEnvironmentMap на OS X, и обе работают одинаково. Хотя на основе комментариев в этой теме, один может быть лучшим выбором, чем другой, в зависимости от среды.
Примечание: я не включил доступ к 'theCaseInsensitiveEnvironmentField', так как это, похоже, специфично для Windows, и у меня не было возможности проверить его, но добавить его было бы просто.
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);
}