Comment définir des variables d'environnement à partir de Java? Je vois que je peux le faire pour les sous-processus utilisant ProcessBuilder
. J'ai plusieurs sous-processus à démarrer, cependant, je préfère donc modifier l'environnement du processus actuel et laisser les sous-processus en hériter.
Il y a un System.getenv(String)
pour obtenir une seule variable d'environnement. Je peux également obtenir un Map
ensemble complet de variables d'environnement avec System.getenv()
. Mais, invoquer put()
cela Map
jette un UnsupportedOperationException
- apparemment, cela signifie que l'environnement est en lecture seule. Et, il n'y a pas System.setenv()
.
Alors, existe-t-il un moyen de définir des variables d'environnement dans le processus en cours d'exécution? Si c'est le cas, comment? Sinon, quelle est la justification? (Est-ce parce que c'est Java et que je ne devrais donc pas faire de mauvaises choses obsolètes non portables comme toucher mon environnement?) Et sinon, de bonnes suggestions pour gérer les changements de variables d'environnement que je vais devoir alimenter à plusieurs sous-processus?
la source
Réponses:
Je pense que vous avez mis le doigt sur la tête.
Un moyen possible d'alléger la charge consisterait à éliminer une méthode
et passer tout
ProcessBuilder
avant de les démarrer.De plus, vous le savez probablement déjà, mais vous pouvez démarrer plusieurs processus avec le même
ProcessBuilder
. Donc, si vos sous-processus sont les mêmes, vous n'avez pas besoin de refaire cette configuration encore et encore.la source
Pour une utilisation dans des scénarios où vous devez définir des valeurs d'environnement spécifiques pour les tests unitaires, vous pouvez trouver le hack suivant utile. Il modifiera les variables d'environnement dans la JVM (assurez-vous donc de réinitialiser toutes les modifications après votre test), mais ne modifiera pas votre environnement système.
J'ai trouvé qu'une combinaison des deux hacks sales d'Edward Campbell et anonyme fonctionne mieux, car l'un ne fonctionne pas sous Linux, l'autre ne fonctionne pas sous Windows 7. Donc, pour obtenir un hack diabolique multiplateforme, je les ai combinés:
Cela fonctionne comme un charme. Remerciements complets aux deux auteurs de ces hacks.
la source
import java.lang.reflect.Field;
Ou pour ajouter / mettre à jour une seule var et supprimer la boucle selon la suggestion de thejoshwolfe.
la source
Class<?> cl = env.getClass();
place de cela pour la boucle?la source
sur Android, l'interface est exposée via Libcore.os comme une sorte d'API cachée.
La classe Libcore ainsi que l'interface OS sont publiques. Juste la déclaration de classe est manquante et doit être montrée à l'éditeur de liens. Pas besoin d'ajouter les classes à l'application, mais cela ne fait pas de mal si elle est incluse.
la source
throws ErrnoException
avecthrows Exception
.Os.setEnv
maintenant. developer.android.com/reference/android/system/… , java.lang.String, boolean)Linux uniquement
Définition de variables d'environnement uniques (d'après la réponse d'Edward Campbell):
Usage:
Tout d'abord, placez la méthode dans la classe de votre choix, par exemple SystemUtil. Appelez-le ensuite statiquement:
Si vous appelez
System.getenv("SHELL")
après cela, vous reviendrez"/bin/bash"
.la source
Il s'agit d'une combinaison de la réponse de @ paul-blair convertie en Java qui comprend des nettoyages signalés par paul blair et quelques erreurs qui semblent avoir été dans le code de @pushy qui est composé de @Edward Campbell et anonyme.
Je ne peux pas souligner à quel point ce code doit être utilisé UNIQUEMENT dans les tests et est extrêmement hacky. Mais pour les cas où vous avez besoin de la configuration de l'environnement dans les tests, c'est exactement ce dont j'avais besoin.
Cela inclut également quelques touches mineures qui permettent au code de fonctionner sur les deux Windows fonctionnant sur
ainsi que Centos fonctionnant sur
La mise en oeuvre:
la source
Il s'avère que la solution de @ pushy / @ anonymous / @ Edward Campbell ne fonctionne pas sur Android car Android n'est pas vraiment Java. Plus précisément, Android n'en a pas
java.lang.ProcessEnvironment
du tout. Mais cela s'avère plus facile sous Android, il suffit de faire un appel JNI à POSIXsetenv()
:En C / JNI:
Et en Java:
la source
Comme la plupart des gens qui ont trouvé ce fil, j'écrivais des tests unitaires et je devais modifier les variables d'environnement pour définir les conditions correctes pour l'exécution du test. Cependant, j'ai trouvé que les réponses les plus votées avaient des problèmes et / ou étaient très cryptiques ou trop compliquées. J'espère que cela aidera les autres à trier la solution plus rapidement.
Tout d'abord, j'ai finalement trouvé la solution de @Hubert Grzeskowiak la plus simple et cela a fonctionné pour moi. J'aurais aimé y arriver en premier. Il est basé sur la réponse de @Edward Campbell, mais sans compliquer la recherche de boucle.
Cependant, j'ai commencé avec la solution de @ pushy, qui a obtenu le plus de votes positifs. Il s'agit d'un combo de @anonymous et @Edward Campbell's. @pushy affirme que les deux approches sont nécessaires pour couvrir les environnements Linux et Windows. Je suis sous OS X et je trouve que les deux fonctionnent (une fois qu'un problème avec l'approche @anonymous est résolu). Comme d'autres l'ont noté, cette solution fonctionne la plupart du temps, mais pas tous.
Je pense que la source de la plupart des confusions vient de la solution de @ anonymous opérant sur le champ 'theEnvironment'. En regardant la définition de la structure ProcessEnvironment , 'theEnvironment' n'est pas une Map <String, String> mais plutôt une Map <Variable, Value>. L'effacement de la carte fonctionne correctement, mais l'opération putAll reconstruit la carte en Map <String, String>, ce qui peut potentiellement poser des problèmes lorsque des opérations ultérieures opèrent sur la structure de données à l'aide de l'API normale qui attend Map <Variable, Value>. De plus, l'accès / la suppression d'éléments individuels est un problème. La solution consiste à accéder indirectement à «l'environnement» via «l'environnement non modifiable». Mais puisque c'est un type UnmodifiableMapl'accès doit se faire via la variable privée 'm' de type UnmodifiableMap. Voir getModifiableEnvironmentMap2 dans le code ci-dessous.
Dans mon cas, j'ai dû supprimer certaines des variables d'environnement pour mon test (les autres doivent rester inchangées). Ensuite, j'ai voulu restaurer les variables d'environnement à leur état antérieur après le test. Les routines ci-dessous rendent cela simple. J'ai testé les deux versions de getModifiableEnvironmentMap sur OS X, et les deux fonctionnent de manière équivalente. Bien que basé sur les commentaires de ce fil, l'un peut être un meilleur choix que l'autre en fonction de l'environnement.
Remarque: Je n'ai pas inclus l'accès au 'theCaseInsensitiveEnvironmentField' car cela semble être spécifique à Windows et je n'avais aucun moyen de le tester, mais l'ajouter devrait être simple.
la source
En fouillant en ligne, il semble qu'il soit possible de le faire avec JNI. Vous devrez alors appeler Poutenv () depuis C, et vous devrez (vraisemblablement) le faire d'une manière qui fonctionne à la fois sur Windows et UNIX.
Si tout cela peut être fait, il ne serait sûrement pas trop difficile pour Java lui-même de supporter cela au lieu de me mettre dans une veste droite.
Un ami parlant Perl ailleurs suggère que cela est dû au fait que les variables d'environnement sont globales au processus et que Java s'efforce d'obtenir une bonne isolation pour une bonne conception.
la source
LD_LIBRARY_PATH
avant d'appelerRuntime.loadLibrary()
; l'dlopen()
appel qu'il invoque regarde l' environnement réel , pas l'idée de Java de la même chose).J'ai essayé la réponse de Pushy ci-dessus et cela a fonctionné pour la plupart. Cependant, dans certaines circonstances, je verrais cette exception:
Cela se produit lorsque la méthode a été appelée plusieurs fois, en raison de la mise en œuvre de certaines classes internes de
ProcessEnvironment.
Si lasetEnv(..)
méthode est appelée plusieurs fois, lorsque les clés sont récupérées de latheEnvironment
carte, elles sont désormais des chaînes (ayant été insérées dans en tant que chaînes par la première invocation desetEnv(...)
) et ne peut pas être converti en type générique de la carte,Variable,
qui est une classe interne privée deProcessEnvironment.
Une version fixe (en Scala), est ci-dessous. Espérons que ce ne soit pas trop difficile à transférer dans Java.
la source
import java.lang.{Class => JavaClass}
.Ceci est la version maléfique de Kotlin du mal de @ pushy réponse de =)
Il fonctionne au moins sur macOS Mojave.
la source
Si vous travaillez avec SpringBoot, vous pouvez ajouter en spécifiant la variable d'environnement dans la propriété suivante:
la source
jythonvariante basée sur la réponse de @ pushy , fonctionne sur Windows.
Usage:
la source
La réponse de Tim Ryan a fonctionné pour moi ... mais je le voulais pour Groovy (contexte Spock par exemple), et simplissimo:
la source
Une version dans Kotlin, dans cet algorithme, j'ai créé un décorateur qui vous permet de définir et d'obtenir des variables de l'environnement.
la source
Implémentation de Kotlin que j'ai récemment faite sur la base de la réponse d'Edward:
la source
Vous pouvez passer des paramètres dans votre processus Java initial avec -D:
la source
System.getProperty
et ne sont pas les mêmes queSystem.getenv
. En outre, laSystem
classe permet également de définir ces propriétés statiquement à l'aide desetProperty