|
19 | 19 |
|
20 | 20 | import java.io.File; |
21 | 21 | import java.lang.reflect.Field; |
22 | | -import java.lang.reflect.Modifier; |
| 22 | +import java.lang.reflect.Method; |
23 | 23 | import java.nio.charset.StandardCharsets; |
24 | 24 | import java.nio.file.Files; |
25 | 25 | import java.security.Permission; |
26 | 26 | import java.util.Collection; |
| 27 | +import java.util.Locale; |
27 | 28 | import java.util.Map; |
28 | 29 | import java.util.concurrent.TimeUnit; |
29 | 30 | import java.util.stream.Collectors; |
@@ -230,21 +231,49 @@ private static void restoreEnvironment() throws Exception { |
230 | 231 | * We modify the JVM's environment variables here. This is necessary for the end-to-end test |
231 | 232 | * because Flink's CliFrontend requires a Flink configuration file for which the location can only |
232 | 233 | * be set using the {@code ConfigConstants.ENV_FLINK_CONF_DIR} environment variable. |
| 234 | + * |
| 235 | + * <p>On Unix, {@code theEnvironment} uses {@code Variable}/{@code Value} keys; {@code putAll} |
| 236 | + * with {@code String} keys does not work for {@code System.getenv(String)} lookups. |
233 | 237 | */ |
| 238 | + @SuppressWarnings("unchecked") |
234 | 239 | private static void modifyEnv(Map<String, String> env) throws Exception { |
235 | 240 | Class processEnv = Class.forName("java.lang.ProcessEnvironment"); |
236 | | - Field envField = processEnv.getDeclaredField("theUnmodifiableEnvironment"); |
| 241 | + Field theEnvironmentField = processEnv.getDeclaredField("theEnvironment"); |
| 242 | + theEnvironmentField.setAccessible(true); |
| 243 | + Map<Object, Object> envMap = (Map<Object, Object>) theEnvironmentField.get(null); |
| 244 | + envMap.clear(); |
237 | 245 |
|
238 | | - Field modifiersField = Field.class.getDeclaredField("modifiers"); |
239 | | - modifiersField.setAccessible(true); |
240 | | - modifiersField.setInt(envField, envField.getModifiers() & ~Modifier.FINAL); |
241 | | - |
242 | | - envField.setAccessible(true); |
243 | | - envField.set(null, env); |
244 | | - envField.setAccessible(false); |
| 246 | + Class<?> variableClass = null; |
| 247 | + Class<?> valueClass = null; |
| 248 | + try { |
| 249 | + variableClass = Class.forName("java.lang.ProcessEnvironment$Variable"); |
| 250 | + valueClass = Class.forName("java.lang.ProcessEnvironment$Value"); |
| 251 | + } catch (ClassNotFoundException e) { |
| 252 | + // Windows: theEnvironment uses String keys. |
| 253 | + } |
| 254 | + if (variableClass != null && valueClass != null) { |
| 255 | + Method valueOfVariable = variableClass.getDeclaredMethod("valueOf", String.class); |
| 256 | + Method valueOfValue = valueClass.getDeclaredMethod("valueOf", String.class); |
| 257 | + valueOfVariable.setAccessible(true); |
| 258 | + valueOfValue.setAccessible(true); |
| 259 | + for (Map.Entry<String, String> entry : env.entrySet()) { |
| 260 | + envMap.put( |
| 261 | + valueOfVariable.invoke(null, entry.getKey()), |
| 262 | + valueOfValue.invoke(null, entry.getValue())); |
| 263 | + } |
| 264 | + } else { |
| 265 | + envMap.putAll(env); |
| 266 | + } |
245 | 267 |
|
246 | | - modifiersField.setInt(envField, envField.getModifiers() & Modifier.FINAL); |
247 | | - modifiersField.setAccessible(false); |
| 268 | + if (System.getProperty("os.name", "").toLowerCase(Locale.ROOT).startsWith("windows")) { |
| 269 | + Field ciEnvField = processEnv.getDeclaredField("theCaseInsensitiveEnvironment"); |
| 270 | + ciEnvField.setAccessible(true); |
| 271 | + Map<String, String> ciEnvMap = (Map<String, String>) ciEnvField.get(null); |
| 272 | + if (ciEnvMap != null) { |
| 273 | + ciEnvMap.clear(); |
| 274 | + ciEnvMap.putAll(env); |
| 275 | + } |
| 276 | + } |
248 | 277 | } |
249 | 278 |
|
250 | 279 | /** Prevents the CliFrontend from calling System.exit. */ |
|
0 commit comments