Como a maioria das pessoas que encontrou esse encadeamento, eu estava escrevendo alguns testes de unidade e precisava modificar as variáveis de ambiente para definir as condições corretas para a execução do teste. No entanto, descobri que as respostas mais votadas tinham alguns problemas e / ou eram muito enigmáticas ou excessivamente complicadas. Espero que isso ajude outras pessoas a resolver a solução mais rapidamente.
Primeiro, finalmente achei a solução do @Hubert Grzeskowiak a mais simples e funcionou para mim. Eu gostaria de ter chegado a esse primeiro. É baseado na resposta de @Edward Campbell, mas sem a complicada pesquisa de loop.
No entanto, comecei com a solução @ pushy, que obteve o maior número de votos. É uma combinação de @anonymous e @Edward Campbell's. A @pushy afirma que as duas abordagens são necessárias para cobrir os ambientes Linux e Windows. Estou executando no OS X e acho que ambos funcionam (uma vez que um problema com a abordagem anônima é corrigido). Como outros observaram, essa solução funciona na maioria das vezes, mas não em todas.
Acho que a fonte da maior parte da confusão vem da solução da @ anonymous operando no campo 'theEnvironment'. Observando a definição da estrutura ProcessEnvironment , 'theEnvironment' não é um Mapa <String, String>, mas sim um Mapa <Variável, Valor>. A limpeza do mapa funciona bem, mas a operação putAll reconstrói o mapa como Map <String, String>, o que potencialmente causa problemas quando operações subsequentes operam na estrutura de dados usando a API normal que espera Map <Variable, Value>. Além disso, acessar / remover elementos individuais é um problema. A solução é acessar indiretamente o 'ambiente' através do 'ambiente não modificável'. Mas como esse é um tipo UnmodifiableMapo acesso deve ser feito através da variável privada 'm' do tipo UnmodifiableMap. Veja getModifiableEnvironmentMap2 no código abaixo.
No meu caso, eu precisei remover algumas das variáveis de ambiente para o meu teste (as outras devem permanecer inalteradas). Depois, quis restaurar as variáveis de ambiente ao seu estado anterior após o teste. As rotinas abaixo tornam isso fácil de fazer. Testei as duas versões do getModifiableEnvironmentMap no OS X e as duas funcionam de maneira equivalente. Embora com base nos comentários deste tópico, uma pode ser uma escolha melhor que a outra, dependendo do ambiente.
Nota: eu não incluí o acesso ao 'theCaseInsensitiveEnvironmentField', pois parece ser específico do Windows e não tinha como testá-lo, mas a adição deve ser direta.
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);
}