我们可以在JDK 17中设置运行时的java环境吗

问题描述 投票:0回答:1

我正在尝试在从 Java 8 迁移到 Java 17 的 Java 应用程序中使用反射在运行时设置环境变量。以前在 Java 8 中,我能够使用反射修改环境变量以访问 Collections.UnmodifyingMap 中的底层映射.

但是,迁移到 Java 17 后,由于 Java 平台模块系统的强封装性,我收到以下错误:

java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.Map java.util.Collections$UnmodifiableMap.m accessible: module java.base does not "opens java.util" to unnamed module

虽然我知道我可以使用 --add-opens java.base/java.util=ALL-UNNAMED 作为解决方法,但我正在寻找一种不需要修改 JVM 参数的更好的解决方案。

我尝试使用在 Java 8 中有效、在 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)
    }
}

我期望能够在运行时修改环境变量,但是 Java 17 的模块系统阻止访问这些内部实现并出现错误:

“java.lang.reflect.InaccessibleObjectException:无法使字段私有最终 java.util.Map java.util.Collections$UnmodifyingMap.m 可访问:模块 java.base 不会“向未命名模块“打开 java.util””

我想避免使用 --add-opens 标志,因为它感觉像是一种解决方法而不是正确的解决方案。我正在寻找一种适用于 Java 17 安全模型的干净替代方法。

java reflection environment-variables java-17 java-platform-module-system
1个回答
0
投票

对于单元测试,您可以专门使用一些实用程序来实现此目的。它们允许您使用指定环境变量的给定值来测试代码。例如,有Kotest系统扩展

withEnvironment("FooKey", "BarValue") {
    System.getenv("FooKey") shouldBe "BarValue" // System environment overridden!
}

如果您没有使用Kotest框架,您可以使用JUnit Pioneer

@Test
@SetEnvironmentVariable(key = "some variable", value = "new value")
void testSet() {
    assertThat(System.getenv("some variable")).isEqualTo("new value");
}
© www.soinside.com 2019 - 2024. All rights reserved.