¿Cómo configuro las variables de entorno de Java? Veo que puedo hacer esto para subprocesos usando ProcessBuilder
. Sin embargo, tengo varios subprocesos para comenzar, así que prefiero modificar el entorno del proceso actual y dejar que los subprocesos lo hereden.
Hay una System.getenv(String)
para obtener una sola variable de entorno. También puedo obtener una Map
del conjunto completo de variables de entorno con System.getenv()
. Pero, recurrir put()
a eso Map
arroja un UnsupportedOperationException
- aparentemente significan que el medio ambiente es de solo lectura. Y no hay System.setenv()
.
Entonces, ¿hay alguna forma de establecer variables de entorno en el proceso actualmente en ejecución? ¿Si es así, cómo? Si no, ¿cuál es la razón? (¿Es porque esto es Java y, por lo tanto, no debería estar haciendo cosas obsoletas mal portables como tocar mi entorno?) Y si no es así, ¿alguna buena sugerencia para administrar los cambios de variables de entorno que voy a necesitar para alimentar a varios? subprocesos?
fuente
Respuestas:
Creo que has dado en el clavo.
Una posible forma de aliviar la carga sería factorizar un método
y pasar cualquier
ProcessBuilder
s antes de comenzar.Además, probablemente ya lo sepas, pero puedes iniciar más de un proceso con el mismo
ProcessBuilder
. Entonces, si sus subprocesos son los mismos, no necesita hacer esta configuración una y otra vez.fuente
Para su uso en escenarios en los que necesita establecer valores de entorno específicos para pruebas unitarias, puede encontrar útil el siguiente truco. Cambiará las variables de entorno en toda la JVM (así que asegúrese de restablecer cualquier cambio después de su prueba), pero no alterará el entorno de su sistema.
Descubrí que una combinación de los dos hacks sucios de Edward Campbell y anónimo funciona mejor, ya que uno de ellos no funciona bajo Linux, uno no funciona bajo Windows 7. Entonces, para obtener un malvado truco multiplataforma, los combiné:
Esto funciona como un encanto. Créditos completos a los dos autores de estos hacks.
fuente
import java.lang.reflect.Field;
O para agregar / actualizar una única var y eliminar el bucle según la sugerencia de thejoshwolfe.
fuente
Class<?> cl = env.getClass();
lugar de eso para el bucle?fuente
en Android, la interfaz se expone a través de Libcore.os como una especie de API oculta.
La clase Libcore y el sistema operativo de la interfaz son públicos. Solo falta la declaración de clase y debe mostrarse al vinculador. No es necesario agregar las clases a la aplicación, pero tampoco hace daño si se incluye.
fuente
throws ErrnoException
athrows Exception
.Os.setEnv
ahora. developer.android.com/reference/android/system/… , java.lang.String, boolean)Solo Linux
Establecer variables de entorno individuales (basadas en la respuesta de Edward Campbell):
Uso:
Primero, coloque el método en la clase que desee, por ejemplo, SystemUtil. Entonces llámalo estáticamente:
Si llamas
System.getenv("SHELL")
después de esto, volverás"/bin/bash"
.fuente
Esta es una combinación de la respuesta de @ paul-blair convertida a Java que incluye algunas limpiezas señaladas por paul blair y algunos errores que parecen haber estado dentro del código de @pushy que está compuesto por @Edward Campbell y anónimo.
No puedo enfatizar cuánto se debe usar SÓLO este código en las pruebas y es extremadamente hacky. Pero para los casos en que necesita la configuración del entorno en las pruebas, es exactamente lo que necesitaba.
Esto también incluye algunos pequeños toques míos que permiten que el código funcione tanto en Windows como en
así como Centos corriendo en
La implementación:
fuente
Resulta que la solución de @ pushy / @ anonymous / @ Edward Campbell no funciona en Android porque Android no es realmente Java. Específicamente, Android no tiene
java.lang.ProcessEnvironment
nada. Pero resulta ser más fácil en Android, solo necesitas hacer una llamada JNI a POSIXsetenv()
:En C / JNI:
Y en Java:
fuente
Como la mayoría de las personas que han encontrado este hilo, estaba escribiendo algunas pruebas unitarias y necesitaba modificar las variables de entorno para establecer las condiciones correctas para que se ejecutara la prueba. Sin embargo, descubrí que las respuestas más votadas tenían algunos problemas y / o eran muy crípticas o demasiado complicadas. Esperemos que esto ayude a otros a resolver la solución más rápidamente.
En primer lugar, finalmente encontré que la solución de @Hubert Grzeskowiak era la más simple y funcionó para mí. Desearía haber venido a eso primero. Se basa en la respuesta de @Edward Campbell, pero sin la complicación de la búsqueda en bucle.
Sin embargo, comencé con la solución de @ pushy, que obtuvo la mayor cantidad de votos. Es una combinación de @anonymous y @Edward Campbell's. @pushy afirma que ambos enfoques son necesarios para cubrir los entornos de Linux y Windows. Estoy ejecutando bajo OS X y encuentro que ambos funcionan (una vez que se soluciona un problema con el enfoque @anonymous). Como otros han señalado, esta solución funciona la mayor parte del tiempo, pero no todo.
Creo que la fuente de la mayor parte de la confusión proviene de la solución de @ anonymous que opera en el campo 'theEnvironment'. Mirando la definición de la estructura ProcessEnvironment , 'theEnvironment' no es un Map <String, String> sino un Map <Variable, Value>. Borrar el mapa funciona bien, pero la operación putAll reconstruye el mapa como Map <String, String>, lo que potencialmente causa problemas cuando las operaciones posteriores operan en la estructura de datos utilizando la API normal que espera Map <Variable, Value>. Además, acceder / eliminar elementos individuales es un problema. La solución es acceder indirectamente a 'theEnvironment' a través de 'theUnmodifiableEnvironment'. Pero como este es un tipo UnmodifiableMapel acceso debe hacerse a través de la variable privada 'm' del tipo UnmodifiableMap. Vea getModifiableEnvironmentMap2 en el código a continuación.
En mi caso, necesitaba eliminar algunas de las variables de entorno para mi prueba (las otras no deberían modificarse). Luego quise restaurar las variables de entorno a su estado anterior después de la prueba. Las rutinas a continuación lo hacen sencillo. Probé ambas versiones de getModifiableEnvironmentMap en OS X, y ambas funcionan de manera equivalente. Aunque basado en los comentarios en este hilo, uno puede ser una mejor opción que el otro dependiendo del entorno.
Nota: No incluí el acceso al 'theCaseInsensitiveEnvironmentField' ya que parece ser específico de Windows y no tenía forma de probarlo, pero agregarlo debería ser sencillo.
fuente
Buscando en línea, parece que podría ser posible hacer esto con JNI. Entonces tendría que hacer una llamada a putenv () desde C, y (presumiblemente) tendría que hacerlo de una manera que funcionara tanto en Windows como en UNIX.
Si se puede hacer todo eso, seguramente no sería demasiado difícil para Java soportar esto en lugar de ponerme una camisa de fuerza.
Un amigo que habla Perl en otro lugar sugiere que esto se debe a que las variables de entorno son procesos globales y Java se esfuerza por un buen aislamiento para un buen diseño.
fuente
LD_LIBRARY_PATH
antes de llamarRuntime.loadLibrary()
; ladlopen()
llamada que invoca se ve en el entorno real , no en la idea de Java de lo mismo).Intenté la respuesta de Pushy arriba y funcionó en su mayor parte. Sin embargo, en ciertas circunstancias, vería esta excepción:
Esto sucede cuando se llama al método más de una vez, debido a la implementación de ciertas clases internas de
ProcessEnvironment.
Si elsetEnv(..)
método se llama más de una vez, cuando las claves se recuperan deltheEnvironment
mapa, ahora son cadenas (después de haber sido colocadas en como cadenas por la primera invocación desetEnv(...)
) y no se pueden convertir al tipo genérico del mapa,Variable,
que es una clase interna privada deProcessEnvironment.
Una versión fija (en Scala), está debajo. Esperemos que no sea demasiado difícil de transferir a Java.
fuente
import java.lang.{Class => JavaClass}
.Esta es la versión malvada de Kotlin de la respuesta malvada de @ pushy =)
Está funcionando en macOS Mojave al menos.
fuente
Si trabaja con SpringBoot, puede agregar especificando la variable ambiental en la siguiente propiedad:
fuente
jythonvariante basada en la respuesta de @ pushy , funciona en windows.
Uso:
fuente
La respuesta de Tim Ryan funcionó para mí ... pero la quería para Groovy (por ejemplo, el contexto de Spock) y simplissimo:
fuente
Una versión en Kotlin, en este algoritmo, creé un decorador que le permite establecer y obtener variables del entorno.
fuente
Implementación de Kotlin que hice recientemente en base a la respuesta de Edward:
fuente
Puede pasar parámetros a su proceso inicial de Java con -D:
fuente
System.getProperty
y no son los mismos queSystem.getenv
. Además, laSystem
clase también permite establecer estas propiedades estáticamente usandosetProperty