Bagaimana cara mengatur variabel lingkungan dari Java? Saya melihat bahwa saya dapat melakukan ini untuk menggunakan subproses ProcessBuilder
. Saya memiliki beberapa subproses untuk memulai, jadi saya lebih suka memodifikasi lingkungan proses saat ini dan membiarkan subproses mewarisinya.
Ada System.getenv(String)
untuk mendapatkan variabel lingkungan tunggal. Saya juga bisa mendapatkan satu Map
set variabel lingkungan lengkap dengan System.getenv()
. Tapi, memanggil put()
itu Map
melempar UnsupportedOperationException
- tampaknya mereka bermaksud agar lingkungan hanya dibaca. Dan tidak ada System.setenv()
.
Jadi, apakah ada cara untuk mengatur variabel lingkungan dalam proses yang sedang berjalan? Jika ya, bagaimana caranya? Jika tidak, apa alasannya? (Apakah ini karena Jawa dan karena itu saya tidak boleh melakukan hal-hal usang yang tidak dapat ditiru seperti menyentuh lingkungan saya?) Dan jika tidak, ada saran bagus untuk mengelola perubahan variabel lingkungan yang akan perlu saya beri makan ke beberapa subproses?
sumber
Jawaban:
Saya pikir Anda telah memukul paku di kepala.
Cara yang mungkin untuk meringankan beban adalah dengan memfaktorkan suatu metode
dan melewati apa pun
ProcessBuilder
melalui itu sebelum memulai mereka.Juga, Anda mungkin sudah mengetahui hal ini, tetapi Anda dapat memulai lebih dari satu proses dengan proses yang sama
ProcessBuilder
. Jadi jika subproses Anda sama, Anda tidak perlu melakukan pengaturan ini berulang-ulang.sumber
Untuk digunakan dalam skenario di mana Anda perlu menetapkan nilai lingkungan spesifik untuk pengujian unit, Anda mungkin menemukan hack berikut berguna. Ini akan mengubah variabel lingkungan di seluruh JVM (jadi pastikan Anda mengatur ulang setiap perubahan setelah pengujian Anda), tetapi tidak akan mengubah lingkungan sistem Anda.
Saya menemukan bahwa kombinasi dari dua peretasan kotor oleh Edward Campbell dan anonim berfungsi paling baik, karena salah satu dari itu tidak bekerja di bawah linux, satu tidak bekerja di bawah windows 7. Jadi untuk mendapatkan peretas jahat multiplatform saya menggabungkannya:
Ini Bekerja seperti pesona. Penghargaan penuh untuk dua penulis peretasan ini.
sumber
import java.lang.reflect.Field;
Atau untuk menambah / memperbarui satu var dan menghapus loop sesuai saran thejoshwolfe.
sumber
Class<?> cl = env.getClass();
itu untuk loop?sumber
pada Android antarmuka diekspos melalui Libcore.os sebagai semacam API tersembunyi.
Kelas Libcore serta OS antarmuka publik. Hanya deklarasi kelas yang hilang dan perlu ditunjukkan ke tautan. Tidak perlu menambahkan kelas ke aplikasi, tetapi juga tidak ada salahnya jika disertakan.
sumber
throws ErrnoException
denganthrows Exception
.Os.setEnv
sekarang. developer.android.com/reference/android/system/… , java.lang.String, boolean)Hanya Linux
Mengatur variabel lingkungan tunggal (berdasarkan jawaban oleh Edward Campbell):
Pemakaian:
Pertama, letakkan metode di kelas yang Anda inginkan, misalnya SystemUtil. Kemudian panggil secara statis:
Jika Anda menelepon
System.getenv("SHELL")
setelah ini, Anda akan"/bin/bash"
kembali.sumber
Ini adalah kombinasi dari jawaban @ paul-blair yang dikonversi ke Java yang mencakup beberapa pembersihan yang ditunjukkan oleh paul blair dan beberapa kesalahan yang tampaknya ada di dalam kode @pushy yang terdiri dari @Edward Campbell dan anonim.
Saya tidak bisa menekankan seberapa banyak kode ini HANYA harus digunakan dalam pengujian dan sangat peretasan. Tetapi untuk kasus-kasus di mana Anda memerlukan pengaturan lingkungan dalam pengujian, itulah yang saya butuhkan.
Ini juga termasuk beberapa sentuhan kecil milik saya yang memungkinkan kode bekerja pada kedua Windows yang sedang berjalan
serta Centos berjalan
Pelaksanaan:
sumber
Ternyata solusi dari @ pushy / @ anonymous / @ Edward Campbell tidak berfungsi di Android karena Android sebenarnya bukan Java. Secara khusus, Android tidak memiliki
java.lang.ProcessEnvironment
sama sekali. Tapi ternyata lebih mudah di Android, Anda hanya perlu melakukan panggilan JNI ke POSIXsetenv()
:Di C / JNI:
Dan di Jawa:
sumber
Seperti kebanyakan orang yang telah menemukan utas ini, saya sedang menulis beberapa unit test dan perlu memodifikasi variabel lingkungan untuk menetapkan kondisi yang benar untuk menjalankan tes. Namun, saya menemukan jawaban yang paling banyak dipilih memiliki beberapa masalah dan / atau sangat samar atau terlalu rumit. Semoga ini akan membantu orang lain untuk memilah solusi lebih cepat.
Pertama, saya akhirnya menemukan solusi @ Hubert Grzeskowiak sebagai solusi paling sederhana dan berhasil bagi saya. Saya berharap saya akan datang ke yang pertama. Ini didasarkan pada jawaban @Edward Campbell, tetapi tanpa menyulitkan untuk pencarian loop.
Namun, saya mulai dengan solusi @ pushy, yang mendapat sebagian besar upvotes. Ini adalah kombinasi dari @anonymous dan @Edward Campbell's. @pushy mengklaim kedua pendekatan diperlukan untuk mencakup lingkungan Linux dan Windows. Saya menjalankan OS X dan menemukan bahwa keduanya berfungsi (sekali masalah dengan pendekatan @anonymous diperbaiki). Seperti yang telah dicatat orang lain, solusi ini bekerja sebagian besar waktu, tetapi tidak semua.
Saya pikir sumber dari sebagian besar kebingungan berasal dari solusi @ anonim yang beroperasi di bidang 'theEnvironment'. Melihat definisi ProcessEnvironment struktur , 'theEnvironment' bukanlah Map <String, String> melainkan Map <Variable, Value>. Mengosongkan peta berfungsi dengan baik, tetapi operasi putAll membangun kembali peta sebuah Peta <String, String>, yang berpotensi menyebabkan masalah ketika operasi selanjutnya beroperasi pada struktur data menggunakan API normal yang mengharapkan Peta <Variable, Value>. Juga, mengakses / menghapus elemen individual adalah masalah. Solusinya adalah mengakses 'theEnvironment' secara tidak langsung melalui 'theUnmnable Ennvironment'. Tapi karena ini adalah tipe UnmodifiableMap , akses harus dilakukan melalui variabel pribadi 'm' dari tipe UnmodifiableMap. Lihat getModifiableEnvironmentMap2 dalam kode di bawah ini.
Dalam kasus saya, saya perlu menghapus beberapa variabel lingkungan untuk pengujian saya (yang lain harus tidak berubah). Kemudian saya ingin mengembalikan variabel lingkungan ke keadaan sebelumnya setelah pengujian. Rutinitas di bawah ini membuatnya mudah untuk dilakukan. Saya menguji kedua versi getModifiableEnvironmentMap pada OS X, dan keduanya bekerja dengan setara. Meskipun berdasarkan komentar di utas ini, yang satu mungkin merupakan pilihan yang lebih baik daripada yang lain tergantung pada lingkungan.
Catatan: Saya tidak memasukkan akses ke 'theCaseInsensitiveEnvironmentField' karena itu sepertinya Windows khusus dan saya tidak punya cara untuk mengujinya, tetapi menambahkan itu harus lurus ke depan.
sumber
Mengaduk-aduk online, sepertinya mungkin untuk melakukan ini dengan JNI. Anda kemudian harus melakukan panggilan ke putenv () dari C, dan Anda (mungkin) harus melakukannya dengan cara yang bekerja pada Windows dan UNIX.
Jika semua itu bisa dilakukan, tentu tidak akan terlalu sulit bagi Jawa sendiri untuk mendukung ini daripada menempatkan saya dalam jaket lurus.
Teman Perl yang berbicara di tempat lain menyarankan bahwa ini karena variabel lingkungan adalah proses global dan Java berusaha keras untuk isolasi yang baik untuk desain yang baik.
sumber
LD_LIBRARY_PATH
sebelum memanggilRuntime.loadLibrary()
;dlopen()
panggilan itu memanggil melihat lingkungan nyata , bukan pada ide Jawa yang sama).Mencoba jawaban pushy di atas dan itu berhasil sebagian besar. Namun, dalam kondisi tertentu, saya akan melihat pengecualian ini:
Ini ternyata terjadi ketika metode dipanggil lebih dari sekali, karena implementasi kelas-kelas dalam tertentu.
ProcessEnvironment.
JikasetEnv(..)
metode dipanggil lebih dari sekali, ketika kunci diambil daritheEnvironment
peta, mereka sekarang adalah string (telah dimasukkan ke dalam sebagai string oleh doa pertamasetEnv(...)
) dan tidak dapat dilemparkan ke tipe generik peta,Variable,
yang merupakan kelas dalam privat dariProcessEnvironment.
Versi tetap (dalam Scala), di bawah. Semoga tidak terlalu sulit untuk dibawa ke Jawa.
sumber
import java.lang.{Class => JavaClass}
.Ini adalah versi jahat Kotlin dari jawaban jahat @ pushy =)
Ini berfungsi di MacOS Mojave setidaknya.
sumber
Jika Anda bekerja dengan SpringBoot Anda bisa menambahkan dengan menentukan variabel lingkungan di properti berikut:
sumber
jythonvarian berdasarkan jawaban @ pushy , bekerja di windows.
Pemakaian:
sumber
Jawaban Tim Ryan bekerja untuk saya ... tapi saya menginginkannya untuk Groovy (konteks Spock misalnya), dan simplissimo:
sumber
Versi di Kotlin, dalam algoritma ini saya membuat dekorator yang memungkinkan Anda untuk mengatur dan mendapatkan variabel dari lingkungan.
sumber
Implementasi Kotlin yang baru-baru ini saya buat berdasarkan jawaban Edward:
sumber
Anda bisa mengirimkan parameter ke proses java awal Anda dengan -D:
sumber
System.getProperty
dan tidak sama denganSystem.getenv
. Selain itu,System
kelas ini juga memungkinkan untuk mengatur properti ini secara statis menggunakansetProperty