287 votos

¿Cómo puedo configurar las variables de entorno de Java?

¿Cómo puedo configurar las variables de entorno de Java? Veo que me puede hacer esto por el uso de subprocesos ProcessBuilder. Tengo varios subprocesos para empezar, aunque, por lo que prefiero modificar el proceso actual del medio ambiente y dejar que los procesos heredar.

Hay un System.getenv(String) para la obtención de una única variable de entorno. También puedo conseguir un Mapa de todo el conjunto de variables de entorno con System.getenv(). Pero las llamadas a poner() en Mapa lanza un UnsupportedOperationException -- aparentemente significan para el medio ambiente a ser de sólo lectura. Y no hay System.setenv().

Así que, ¿hay alguna manera para establecer variables de entorno en el proceso que se ejecuta actualmente? Si es así, ¿cómo? Si no, ¿cuál es la justificación? (Es porque esta es Java y por lo tanto, no debería estar haciendo mal no portátiles obsoletos cosas como tocar mi entorno?) Y si no, cualquier buen sugerencias para la gestión de los cambios de variables de entorno que voy a tener que estar alimentando a varios subprocesos?

231voto

pushy Puntos 4646

Para su uso en escenarios donde es necesario establecer determinados valores de entorno para la unidad de pruebas, usted podría encontrar que el truco útil. Va a cambiar las variables de entorno a lo largo de la JVM (así que asegúrese de restablecer los cambios después de la prueba), pero no altera el entorno del sistema.

He encontrado que una combinación de los dos sucio hacks por Edward Campbell y obras anónimas mejor, como uno de los no funciona bajo linux, no funciona en windows 7. Así que para obtener una multiplataforma mal hack me ha combinado:

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 (NoSuchFieldException 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.clear();
                map.putAll(newenv);
            }
        }
      } catch (Exception e2) {
        e2.printStackTrace();
      }
    } catch (Exception e1) {
        e1.printStackTrace();
    } 
}

Esto Funciona como un encanto. Total que los créditos de los dos autores de estos hacks.

88voto

Michael Myers Puntos 82361

(Es porque esta es Java y por lo tanto, no debería estar haciendo mal no portátiles obsoletos cosas como tocar mi entorno?)

Yo creo que has dado en el clavo en la cabeza.

Un camino posible para aliviar la carga sería el factor de un método

void setUpEnvironment(ProcessBuilder builder) {
    Map<String, String> env = builder.environment();
    // blah blah
}

y a pasar por cualquiera ProcessBuilders a través de él antes de empezar.

También, usted probablemente ya sabes esto, pero usted puede iniciar más de un proceso con el mismo ProcessBuilder. Así que si tu subprocesos son el mismo, usted no necesita hacer este tipo de configuración más y más.

21voto

anonymous Puntos 61
 // este es un sucio hack - pero debe ser aceptable para un unittest.
 private void setNewEnvironmentHack(Map<String, String> newenv) throws Exception
{
 Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
 Campo theEnvironmentField = processEnvironmentClass.getDeclaredfield("theEnvironment");
theEnvironmentField.setAccessible(true);
 Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.clear();
env.putAll(newenv);
 Campo theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredfield("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setaccessible(true);
 Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.clear();
cienv.putAll(newenv);
}

4voto

skiphoppy Puntos 16563

Hurgando en línea, que parece que podría ser posible hacer esto con JNI. Así que tendrías que hacer una llamada a putenv() de C, y d (presumiblemente) tienes que hacerlo de una manera en la que trabajó tanto en Windows como en UNIX.

Si todo lo que se puede hacer, seguramente no sería demasiado duro para Java a este lugar de ponerme en una camisa de fuerza.

Un Perl amigo que habla en otro lugar, sugiere que esto se debe a variables de entorno global del proceso y de Java se está esforzando para un buen aislamiento para un buen diseño.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X