環境変数の取得は、System.getEnv(String)
でも、setEnv など System には存在しない。
Java コード上から環境変数をセットしなければならないケースなんて、そうそうないのだけれど。。。
参考は、How do I set environment variables from Java? - Stack Overflow
リフレクションで無理やりなのですが。。。
@SuppressWarnings("unchecked") protected static void setEnv(String key, String value) { 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.put(key, value); Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment"); theCaseInsensitiveEnvironmentField.setAccessible(true); Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null); cienv.put(key, value); }catch(Exception e){ try{ 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.put(key, value); } } }catch(Exception x){ x.printStackTrace(); } } }
Mapでまとめてセットする。。。
@SuppressWarnings("unchecked") protected static void setEnv(Map<String, String> newenv) { 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(Exception e){ try{ 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.putAll(newenv); } } }catch(Exception x){ x.printStackTrace(); } } }
でも、これらは Java9 以降では java.lang.ProcessEnvironment から取得した theEnvironment フィールドに対して
アクセス権の強制取得、setAccessible(true) を実行したときに
以下のとおり、標準エラー出力(System.err)で、警告(ワーニング)を出力します。
WARNING: Illegal reflective access by xx.xxx.xxx.Xxxx (file:/C:/xxxxxx/target/classes/)
to field java.lang.ProcessEnvironment.theEnvironment
WARNING: Please consider reporting this to the maintainers of xx.xxx.xxx.Xxxx
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
この警告メッセージが出るのを抑制するのに次のようなメソッドを用意して
環境変数をセット実行前に実行しておけば抑制はできます。
public static void ignoreJava9Warning(){ try{ Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); sun.misc.Unsafe u = (sun.misc.Unsafe) theUnsafe.get(null); Class<?> cls = Class.forName("jdk.internal.module.IllegalAccessLogger"); Field logger = cls.getDeclaredField("logger"); u.putObjectVolatile(cls, u.staticFieldOffset(logger), null); }catch(Exception e){ } }
この抑制は、Java8 で無意味です。catch Exception の中に入ります。