আমি জাভা থেকে পরিবেশের পরিবর্তনগুলি কীভাবে সেট করব?


289

আমি জাভা থেকে পরিবেশের পরিবর্তনগুলি কীভাবে সেট করব? আমি দেখতে পাচ্ছি যে আমি এটি ব্যবহার করে সাবপ্রসেসিগুলি করতে পারি canProcessBuilder । যদিও শুরু করার জন্য আমার কাছে বেশ কয়েকটি উপ-প্রক্রিয়া রয়েছে, সুতরাং আমি বরং বর্তমান প্রক্রিয়ার পরিবেশটি সংশোধন করব এবং উপ-প্রক্রিয়াগুলি এটির উত্তরাধিকার সূত্রে সুযোগ দেব।

System.getenv(String)একটি একক পরিবেশের পরিবর্তনশীল পাওয়ার জন্য এখানে রয়েছে । আমি Mapপরিবেশগত ভেরিয়েবলগুলির সাথে একটি সম্পূর্ণ সেটও পেতে পারি System.getenv()। তবে, এটির put()দিকে আহ্বান জানাতে Mapএকটি UnsupportedOperationException- আপাতদৃষ্টিতে এগুলি কেবল পরিবেশের পড়ার জন্য বোঝায়। এবং, নেইSystem.setenv()

সুতরাং, বর্তমানে চলমান প্রক্রিয়াতে পরিবেশের ভেরিয়েবলগুলি সেট করার কোনও উপায় আছে কি? যদি তাই হয়, কিভাবে? তা না হলে যুক্তি কী? (এটি কি জাভা হওয়ায় এবং তাই আমার পরিবেশকে স্পর্শ করার মতো খারাপ অপ্রয়োজনীয় অপ্রচলিত কাজ করা উচিত নয়?) এবং যদি না হয়, তবে পরিবেশের পরিবর্তনশীল পরিবর্তনগুলি পরিচালনার জন্য আমার কোনও ভাল পরামর্শ যা বেশ কয়েকটিকে খাওয়ানো দরকার? subprocesses?


System.getEnv () সর্বজনীন-ইশ হওয়ার উদ্দেশ্যে তৈরি হয়েছে, কিছু কিছু পরিবেশের এমনকি পরিবেশের ভেরিয়েবলগুলি নেই।
b1nary.atr0phy

7
: যারা একটি ইউনিট টেস্টিং ব্যবহারের ক্ষেত্রে এই প্রয়োজনীয় stackoverflow.com/questions/8168884/...
Atifm

উত্তর:


88

(এটি কি জাভা হওয়ার কারণে এবং তাই আমার পরিবেশের স্পর্শ করার মতো খারাপ অপ্রয়োজনীয় অপ্রচলিত কাজ করা উচিত নয়?)

আমি মনে করি আপনি মাথার পেরেকটি আঘাত করেছেন।

বোঝা হ্রাস করার একটি সম্ভাব্য উপায় হ'ল কোনও পদ্ধতি নির্ধারণ করা

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

এবং ProcessBuilderএগুলি শুরু করার আগে এর মাধ্যমে কোনও পাস করুন।

এছাড়াও, আপনি সম্ভবত এটি ইতিমধ্যে জানেন, তবে আপনি এটির মাধ্যমে একাধিক প্রক্রিয়া শুরু করতে পারেন ProcessBuilder। সুতরাং আপনার উপ-প্রসেসগুলি যদি একই হয় তবে আপনার এই সেটআপটি বার বার করার দরকার নেই।


1
এটি লজ্জাজনক ব্যবস্থাপনার পরে এই অশুভ সেটটি, অপ্রচলিত উপ-প্রক্রিয়াগুলি চালানোর জন্য আমাকে অন্য কোনও বহনযোগ্য ভাষা ব্যবহার করতে দেয় না। :)
skiphoppy

18
এস। লট, আমি কোনও পিতামাতার পরিবেশ নির্ধারণ করতে চাইছি না। আমি আমার নিজস্ব পরিবেশ সেট করতে খুঁজছি।
skiphoppy

3
এটি দুর্দান্ত কাজ করে, যদি না এটি অন্য কারও পাঠাগার (যেমন সান এর) প্রক্রিয়া চালু করে।
sullivan-

24
@ b1naryatr0phy আপনি পয়েন্টটি মিস করেছেন। আপনার পরিবেশের ভেরিয়েবলগুলির সাথে কেউ খেলতে পারবেন না কারণ এই ভেরিয়েবলগুলি কোনও প্রক্রিয়াতে স্থানীয় (আপনি উইন্ডোতে যা সেট করেছেন সেটি ডিফল্ট মান)। প্রতিটি প্রক্রিয়া তার নিজস্ব ভেরিয়েবলগুলি পরিবর্তন করতে মুক্ত ... এটির জাভা না থাকলে।
মার্টিনাস

9
জাভা এই সীমাবদ্ধতা একটি পুলিশ কিছুটা আউট। "আপনাকে জাভা এটি করতে চায় না" বাদে জাভা আপনাকে এনভেরি ওয়ার্স সেট না করার কোনও কারণ নেই।
ইয়াননর্টন

232

পরিস্থিতিগুলিতে ব্যবহারের জন্য যেখানে ইউনিট পরীক্ষার জন্য আপনাকে নির্দিষ্ট পরিবেশের মানগুলি নির্ধারণ করতে হবে, আপনি নিম্নলিখিত হ্যাকটিকে দরকারী বলে মনে করতে পারেন। এটি পুরো জেভিএম জুড়ে পরিবেশের পরিবর্তনশীলগুলি পরিবর্তন করবে (সুতরাং আপনার পরীক্ষার পরে আপনি যে কোনও পরিবর্তন পুনরায় সেট করেছেন তা নিশ্চিত করুন) তবে এটি আপনার সিস্টেমের পরিবেশকে পরিবর্তন করবে না।

আমি দেখতে পেলাম যে এডওয়ার্ড ক্যাম্পবেল এবং বেনামে দুটি নোংরা হ্যাকের সংমিশ্রণটি সবচেয়ে ভাল কাজ করে, যেমন একটি লিনাক্সের অধীনে কাজ করে না, কেউ উইন্ডোজের নীচে কাজ করে না So সুতরাং একাধিক প্ল্যাটফর্মের দুষ্ট হ্যাক পাওয়ার জন্য আমি তাদের সংযুক্ত করেছি:

protected static void setEnv(Map<String, String> newenv) throws Exception {
  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) {
    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);
      }
    }
  }
}

এটি একটি কবজ মত কাজ করে। এই হ্যাক দুটি লেখকের সম্পূর্ণ ক্রেডিট।


1
এটি কি কেবল স্মৃতিতে পরিবর্তিত হবে, বা বাস্তবে সিস্টেমের পুরো পরিবেশ পরিবর্তনশীল পরিবর্তন করবে?
শেরভিন আসগরী

36
এটি কেবল স্মৃতিতে পরিবেশের পরিবর্তনশীল পরিবর্তন করবে। এটি পরীক্ষার জন্য ভাল, কারণ আপনি আপনার পরীক্ষার জন্য পরিবেশের পরিবর্তনশীলকে প্রয়োজনীয় হিসাবে সেট করতে পারেন, তবে সিস্টেমগুলিতে vর্ষাকর্মীদের যেমন রয়েছে তেমনই ছেড়ে দিন। আসলে, আমি পরীক্ষার চেয়ে অন্য কোনও উদ্দেশ্যে এই কোডটি ব্যবহার করা থেকে কাউকে দৃ strongly়ভাবে নিরুৎসাহিত করব। এই কোডটি খারাপ ;-)
পুশী

9
এফওয়াইআই হিসাবে, জেভিএম শুরু হয় যখন পরিবেশের ভেরিয়েবলগুলির একটি অনুলিপি তৈরি করে। এটি সেই অনুলিপিটি সম্পাদনা করবে, জেভিএম শুরু হওয়া মূল প্রক্রিয়ার জন্য পরিবেশের পরিবর্তনশীল নয়।
বিড

আমি এটিকে অ্যান্ড্রয়েডে চেষ্টা করে দেখেছি বলে মনে হয় না। অ্যান্ড্রয়েডে অন্য কারও ভাগ্য আছে?
হ্যান্স-ক্রিস্টোফ স্টেইনার

5
অবশ্যই,import java.lang.reflect.Field;
21:44 এ 11

63
public static void set(Map<String, String> newenv) throws Exception {
    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);
        }
    }
}

অথবা একটি একক ভেরি যুক্ত / আপডেট করতে এবং thejoshwolfe এর পরামর্শ অনুসারে লুপটি সরাতে।

@SuppressWarnings({ "unchecked" })
  public static void updateEnv(String name, String val) throws ReflectiveOperationException {
    Map<String, String> env = System.getenv();
    Field field = env.getClass().getDeclaredField("m");
    field.setAccessible(true);
    ((Map<String, String>) field.get(env)).put(name, val);
  }

3
মনে হচ্ছে এটি মেমরিটিতে মানচিত্রটি পরিবর্তন করবে, তবে এটি কি সিস্টেমে মান সংরক্ষণ করবে?
জন অনস্টট

1
ভাল এটি পরিবেশের পরিবর্তনশীলগুলির মেমরি মানচিত্র পরিবর্তন করে। আমার ধারণা, পুরো ব্যবহারের ক্ষেত্রে এটি যথেষ্ট suff @ অ্যাডওয়ার্ড - গোক, এই সমাধানটি প্রথম স্থানে কীভাবে নির্ধারিত হয়েছিল তা কল্পনা করা শক্ত!
অনির্বাণ

13
এটি সিস্টেমে এনভায়রনমেন্ট ভেরিয়েবল পরিবর্তন করবে না, তবে জাভাটির বর্তমান অনুরোধে এগুলি পরিবর্তন করবে। এটি ইউনিট পরীক্ষার জন্য খুব দরকারী।
স্টুয়ার্ট কে

10
Class<?> cl = env.getClass();লুপের পরিবর্তে এর পরিবর্তে কেন ব্যবহার করবেন না?
thejoshwolfe

1
আমি ঠিক তাই খুঁজছিলাম! আমি এমন কোনও কোডের জন্য ইন্টিগ্রেশন টেস্টগুলি লিখছি যা কোনও তৃতীয় পক্ষের সরঞ্জাম ব্যবহার করে যা কোনও কারণে কেবলমাত্র আপনাকে পরিবেশের পরিবর্তনশীল সহ এর অযৌক্তিক স্বল্প ডিফল্ট টাইমআউট দৈর্ঘ্য পরিবর্তন করতে দেয়।
ডেভিড ডিমার

21
// this is a dirty hack - but should be ok for a unittest.
private void setNewEnvironmentHack(Map<String, String> newenv) throws Exception
{
  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.clear();
  env.putAll(newenv);
  Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
  theCaseInsensitiveEnvironmentField.setAccessible(true);
  Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
  cienv.clear();
  cienv.putAll(newenv);
}

17

অ্যান্ড্রয়েডে ইন্টারফেসটি Libcore.os এর মাধ্যমে এক ধরণের লুকানো API হিসাবে প্রকাশিত হয়।

Libcore.os.setenv("VAR", "value", bOverwrite);
Libcore.os.getenv("VAR"));

লাইবকোর ক্লাসের পাশাপাশি ইন্টারফেস ওএস সর্বজনীন। কেবল শ্রেণির ঘোষণাটি অনুপস্থিত এবং লিঙ্কারে দেখানো দরকার। অ্যাপ্লিকেশনটিতে ক্লাস যুক্ত করার দরকার নেই, তবে এটি অন্তর্ভুক্ত করা থাকলে এটি ক্ষতি করে না।

package libcore.io;

public final class Libcore {
    private Libcore() { }

    public static Os os;
}

package libcore.io;

public interface Os {
    public String getenv(String name);
    public void setenv(String name, String value, boolean overwrite) throws ErrnoException;
}

1
Android 4.4.4 (সিএম 11) এ পরীক্ষিত এবং কাজ করছে। দ্রষ্টব্য দ্য শুধুমাত্র সমন্বয় আমি তৈরি প্রতিস্থাপন করা হয়েছিল throws ErrnoExceptionসঙ্গে throws Exception
ডেভিসএনটি

7
এপিআই 21, Os.setEnvএখন আছে। বিকাশকারী.অ্যান্ড্রয়েড / রেফারেন্স / অ্যান্ড্রয়েড / সিস্টেমে /,, জাভা.লং। স্ট্রিং, বুলিয়ান)
জারেড বুরোজ

1
পাই এর নতুন বিধিনিষেধগুলির সাথে এখন সম্ভাব্যভাবে
হ্রাস পেয়েছে

13

শুধুমাত্র লিনাক্স

একক পরিবেশের ভেরিয়েবল সেট করা (এডওয়ার্ড ক্যাম্পবেলের উত্তরের ভিত্তিতে):

public static void setEnv(String key, String value) {
    try {
        Map<String, String> env = System.getenv();
        Class<?> cl = env.getClass();
        Field field = cl.getDeclaredField("m");
        field.setAccessible(true);
        Map<String, String> writableEnv = (Map<String, String>) field.get(env);
        writableEnv.put(key, value);
    } catch (Exception e) {
        throw new IllegalStateException("Failed to set environment variable", e);
    }
}

ব্যবহার:

প্রথমে আপনার পছন্দসই ক্লাসে পদ্ধতিটি রাখুন, যেমন সিস্টেমআপিল। তারপরে এটিকে স্থিরভাবে কল করুন:

SystemUtil.setEnv("SHELL", "/bin/bash");

আপনি যদি এর System.getenv("SHELL")পরে কল করেন তবে আপনি "/bin/bash"ফিরে পাবেন।


উপরের উইন্ডোজ 10 এ কাজ করে না তবে লিনাক্সে কাজ করবে
mengchengfeng

মজাদার. আমি নিজে উইন্ডোজে চেষ্টা করে দেখিনি। আপনি কি একটি ত্রুটি পান, @ মেমচেংফেং?
হুবার্ট গ্রেজস্কোইয়াক

@HubertGrzeskowiak আমরা কোনো ত্রুটি বার্তা দেখতে পাইনি, এটা ঠিক কাজ করে নি ...
mengchengfeng

9

এটি জাভাতে রূপান্তরিত @ পল-ব্লেয়ারের উত্তরের একটি সংমিশ্রণ যা পল ব্লেয়ার দ্বারা নির্দেশিত কিছু ক্লিনআপ এবং কিছু ভুল যা মনে হয় @ পুশির কোডের ভিতরে যা অ্যাডওয়ার্ড ক্যাম্পবেল এবং বেনামে গঠিত includes

এই কোডটি কেবলমাত্র পরীক্ষায় ব্যবহার করা উচিত এবং এটি অত্যন্ত হ্যাকি জোর দিয়ে বলতে পারি না। তবে পরীক্ষাগুলিতে যেখানে আপনার পরিবেশের সেটআপ দরকার তা ক্ষেত্রে এটি আমার প্রয়োজন ঠিক ঠিক।

এটিতে আমার কিছু ছোটখাটো স্পর্শও অন্তর্ভুক্ত যা কোডগুলি উভয় উইন্ডোতে চলতে কাজ করতে দেয়

java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

পাশাপাশি সেন্টোস চলছে

openjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)

রুপায়ণ:

/**
 * Sets an environment variable FOR THE CURRENT RUN OF THE JVM
 * Does not actually modify the system's environment variables,
 *  but rather only the copy of the variables that java has taken,
 *  and hence should only be used for testing purposes!
 * @param key The Name of the variable to set
 * @param value The value of the variable to set
 */
@SuppressWarnings("unchecked")
public static <K,V> void setenv(final String key, final String value) {
    try {
        /// we obtain the actual environment
        final Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
        final Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
        final boolean environmentAccessibility = theEnvironmentField.isAccessible();
        theEnvironmentField.setAccessible(true);

        final Map<K,V> env = (Map<K, V>) theEnvironmentField.get(null);

        if (SystemUtils.IS_OS_WINDOWS) {
            // This is all that is needed on windows running java jdk 1.8.0_92
            if (value == null) {
                env.remove(key);
            } else {
                env.put((K) key, (V) value);
            }
        } else {
            // This is triggered to work on openjdk 1.8.0_91
            // The ProcessEnvironment$Variable is the key of the map
            final Class<K> variableClass = (Class<K>) Class.forName("java.lang.ProcessEnvironment$Variable");
            final Method convertToVariable = variableClass.getMethod("valueOf", String.class);
            final boolean conversionVariableAccessibility = convertToVariable.isAccessible();
            convertToVariable.setAccessible(true);

            // The ProcessEnvironment$Value is the value fo the map
            final Class<V> valueClass = (Class<V>) Class.forName("java.lang.ProcessEnvironment$Value");
            final Method convertToValue = valueClass.getMethod("valueOf", String.class);
            final boolean conversionValueAccessibility = convertToValue.isAccessible();
            convertToValue.setAccessible(true);

            if (value == null) {
                env.remove(convertToVariable.invoke(null, key));
            } else {
                // we place the new value inside the map after conversion so as to
                // avoid class cast exceptions when rerunning this code
                env.put((K) convertToVariable.invoke(null, key), (V) convertToValue.invoke(null, value));

                // reset accessibility to what they were
                convertToValue.setAccessible(conversionValueAccessibility);
                convertToVariable.setAccessible(conversionVariableAccessibility);
            }
        }
        // reset environment accessibility
        theEnvironmentField.setAccessible(environmentAccessibility);

        // we apply the same to the case insensitive environment
        final Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
        final boolean insensitiveAccessibility = theCaseInsensitiveEnvironmentField.isAccessible();
        theCaseInsensitiveEnvironmentField.setAccessible(true);
        // Not entirely sure if this needs to be casted to ProcessEnvironment$Variable and $Value as well
        final Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
        if (value == null) {
            // remove if null
            cienv.remove(key);
        } else {
            cienv.put(key, value);
        }
        theCaseInsensitiveEnvironmentField.setAccessible(insensitiveAccessibility);
    } catch (final ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
        throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+">", e);
    } catch (final NoSuchFieldException e) {
        // we could not find theEnvironment
        final Map<String, String> env = System.getenv();
        Stream.of(Collections.class.getDeclaredClasses())
                // obtain the declared classes of type $UnmodifiableMap
                .filter(c1 -> "java.util.Collections$UnmodifiableMap".equals(c1.getName()))
                .map(c1 -> {
                    try {
                        return c1.getDeclaredField("m");
                    } catch (final NoSuchFieldException e1) {
                        throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+"> when locating in-class memory map of environment", e1);
                    }
                })
                .forEach(field -> {
                    try {
                        final boolean fieldAccessibility = field.isAccessible();
                        field.setAccessible(true);
                        // we obtain the environment
                        final Map<String, String> map = (Map<String, String>) field.get(env);
                        if (value == null) {
                            // remove if null
                            map.remove(key);
                        } else {
                            map.put(key, value);
                        }
                        // reset accessibility
                        field.setAccessible(fieldAccessibility);
                    } catch (final ConcurrentModificationException e1) {
                        // This may happen if we keep backups of the environment before calling this method
                        // as the map that we kept as a backup may be picked up inside this block.
                        // So we simply skip this attempt and continue adjusting the other maps
                        // To avoid this one should always keep individual keys/value backups not the entire map
                        LOGGER.info("Attempted to modify source map: "+field.getDeclaringClass()+"#"+field.getName(), e1);
                    } catch (final IllegalAccessException e1) {
                        throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+">. Unable to access field!", e1);
                    }
                });
    }
    LOGGER.info("Set environment variable <"+key+"> to <"+value+">. Sanity Check: "+System.getenv(key));
}

7

দেখা যাচ্ছে যে @ পুসি / @ বেনামে / @ এডওয়ার্ড ক্যাম্পবেল থেকে সমাধান অ্যান্ড্রয়েডে কাজ করে না কারণ অ্যান্ড্রয়েড আসলে জাভা নয়। বিশেষত, অ্যান্ড্রয়েড মোটেও নেই java.lang.ProcessEnvironment। তবে এটি অ্যান্ড্রয়েডে আরও সহজ হতে পারে, আপনার পসিক্সে কেবল একটি জেএনআই কল করা দরকারsetenv() :

সি / জেএনআইতে:

JNIEXPORT jint JNICALL Java_com_example_posixtest_Posix_setenv
  (JNIEnv* env, jclass clazz, jstring key, jstring value, jboolean overwrite)
{
    char* k = (char *) (*env)->GetStringUTFChars(env, key, NULL);
    char* v = (char *) (*env)->GetStringUTFChars(env, value, NULL);
    int err = setenv(k, v, overwrite);
    (*env)->ReleaseStringUTFChars(env, key, k);
    (*env)->ReleaseStringUTFChars(env, value, v);
    return err;
}

এবং জাভাতে:

public class Posix {

    public static native int setenv(String key, String value, boolean overwrite);

    private void runTest() {
        Posix.setenv("LD_LIBRARY_PATH", "foo", true);
    }
}

5

এই থ্রেডটি খুঁজে পাওয়া বেশিরভাগ লোকের মতো, আমি কিছু ইউনিট পরীক্ষা লিখছিলাম এবং পরীক্ষাটি চালানোর জন্য সঠিক শর্ত নির্ধারণ করার জন্য পরিবেশের পরিবর্তনশীলগুলি সংশোধন করা দরকার। তবে, আমি খুঁজে পেয়েছি সর্বাধিক উত্সাহিত উত্তরগুলির কিছু সমস্যা ছিল এবং / অথবা খুব ক্রিপ্টিক বা অত্যধিক জটিল। আশা করি এটি অন্যদের সমাধান আরও দ্রুত বাছাই করতে সহায়তা করবে।

প্রথমে, আমি অবশেষে @ হুবার্ট গ্রাজেকোইয়াকের সমাধানটি সবচেয়ে সহজ হিসাবে খুঁজে পেয়েছি এবং এটি আমার পক্ষে কাজ করেছে। আমি আশা করি যে আমি প্রথমে এসেছি। এটি @ অ্যাডওয়ার্ড ক্যাম্পবেলের উত্তরের ভিত্তিতে, তবে লুপ অনুসন্ধানে জটিলতা ছাড়াই।

যাইহোক, আমি @ পুশির সমাধান দিয়ে শুরু করেছি, যা সর্বাধিক উত্সাহ পেয়েছে। এটি @ বেনামে এবং @ অ্যাডওয়ার্ড ক্যাম্পবেলের একটি কম্বো। @ পুশি দাবি করেছেন যে লিনাক্স এবং উইন্ডোজ উভয় পরিবেশকেই আবরণ করার জন্য উভয় পদ্ধতিরই প্রয়োজন। আমি ওএস এক্স এর অধীনে চলেছি এবং উভয়ই কাজ খুঁজে পেয়েছি (একবার @ বেনামে পদ্ধতির কোনও সমস্যা স্থির হয়ে গেছে)। অন্যরা যেমন উল্লেখ করেছে যে এই সমাধানটি বেশিরভাগ সময় কার্যকর হয় তবে সমস্তটি নয়।

আমি মনে করি বেশিরভাগ বিভ্রান্তির উত্স @ বেনামের সমাধান 'দ্য এনভায়রনমেন্ট' ক্ষেত্রে কাজ করে from প্রক্রিয়া পরিবেশের পরিবেশ কাঠামোর তাকানো, 'দ্য এনভায়রনমেন্ট' কোনও মানচিত্র <স্ট্রিং, স্ট্রিং> নয় বরং এটি মানচিত্র <পরিবর্তনশীল, মান> ue মানচিত্র সাফ করা ঠিকঠাক কাজ করে তবে পুটএল অপারেশন মানচিত্রটিকে একটি মানচিত্র <স্ট্রিং, স্ট্রিং> পুনর্নির্মাণ করে, যা পরবর্তীকালে অপারেশনগুলি স্বাভাবিক এপিআই ব্যবহার করে ডেটা স্ট্রাকচারে অপারেশন করে যখন সম্ভাব্যত সমস্যা তৈরি করে যা মানচিত্র <পরিবর্তনশীল, মান> আশা করে। এছাড়াও, পৃথক উপাদান অ্যাক্সেস / অপসারণ একটি সমস্যা। সমাধানটি 'TheUnmodifiableEnटका' এর মাধ্যমে অপ্রত্যক্ষভাবে 'পরিবেশ' অ্যাক্সেস করা। তবে যেহেতু এটি টাইপ আনমোডিফাইয়েবল ম্যাপ সংজ্ঞাটি দেখে অ্যাক্সেসটি আনমোডেফাইয়েবলম্যাপ টাইপের ব্যক্তিগত ভেরিয়েবল 'এম' এর মাধ্যমে করতে হবে। নীচের কোডে getModifiableEnomotMap2 দেখুন।

আমার ক্ষেত্রে আমার পরীক্ষার জন্য কিছু পরিবেশের ভেরিয়েবল অপসারণ করা দরকার (অন্যগুলি অপরিবর্তিত হওয়া উচিত)। তারপরে আমি পরীক্ষার পরে পরিবেশের পরিবর্তনগুলি তাদের পূর্বের অবস্থায় ফিরিয়ে আনতে চেয়েছিলাম। নীচের রুটিনগুলি তা করতে সরাসরি এগিয়ে দেয়। আমি ওএস এক্স-তে getModifiableEnਵਰমেন্টম্যাপের উভয় সংস্করণ পরীক্ষা করেছি এবং উভয়ই সমানভাবে কাজ করে। যদিও এই থ্রেডের মন্তব্যের ভিত্তিতে, পরিবেশের উপর নির্ভর করে অন্যের চেয়ে ভাল পছন্দ হতে পারে।

দ্রষ্টব্য: আমি 'কেসআইসেন্সিটিভ এএনভায়রনফিল্ড' এ অ্যাক্সেস অন্তর্ভুক্ত করি নি যেহেতু এটি উইন্ডোজ নির্দিষ্ট বলে মনে হচ্ছে এবং এটি পরীক্ষা করার আমার কাছে কোনও উপায় ছিল না, তবে এটি যুক্ত করা সরাসরি হওয়া উচিত।

private Map<String, String> getModifiableEnvironmentMap() {
    try {
        Map<String,String> unmodifiableEnv = System.getenv();
        Class<?> cl = unmodifiableEnv.getClass();
        Field field = cl.getDeclaredField("m");
        field.setAccessible(true);
        Map<String,String> modifiableEnv = (Map<String,String>) field.get(unmodifiableEnv);
        return modifiableEnv;
    } catch(Exception e) {
        throw new RuntimeException("Unable to access writable environment variable map.");
    }
}

private Map<String, String> getModifiableEnvironmentMap2() {
    try {
        Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
        Field theUnmodifiableEnvironmentField = processEnvironmentClass.getDeclaredField("theUnmodifiableEnvironment");
        theUnmodifiableEnvironmentField.setAccessible(true);
        Map<String,String> theUnmodifiableEnvironment = (Map<String,String>)theUnmodifiableEnvironmentField.get(null);

        Class<?> theUnmodifiableEnvironmentClass = theUnmodifiableEnvironment.getClass();
        Field theModifiableEnvField = theUnmodifiableEnvironmentClass.getDeclaredField("m");
        theModifiableEnvField.setAccessible(true);
        Map<String,String> modifiableEnv = (Map<String,String>) theModifiableEnvField.get(theUnmodifiableEnvironment);
        return modifiableEnv;
    } catch(Exception e) {
        throw new RuntimeException("Unable to access writable environment variable map.");
    }
}

private Map<String, String> clearEnvironmentVars(String[] keys) {

    Map<String,String> modifiableEnv = getModifiableEnvironmentMap();

    HashMap<String, String> savedVals = new HashMap<String, String>();

    for(String k : keys) {
        String val = modifiableEnv.remove(k);
        if (val != null) { savedVals.put(k, val); }
    }
    return savedVals;
}

private void setEnvironmentVars(Map<String, String> varMap) {
    getModifiableEnvironmentMap().putAll(varMap);   
}

@Test
public void myTest() {
    String[] keys = { "key1", "key2", "key3" };
    Map<String, String> savedVars = clearEnvironmentVars(keys);

    // do test

    setEnvironmentVars(savedVars);
}

ধন্যবাদ, এটি আমার ব্যবহারের ক্ষেত্রে এবং ম্যাক ওএস এক্স এর অধীনেও ছিল।
রাফায়েল গোনালভেস 15

এটিকে এতটা পছন্দ করেছেন আমি গ্রোভির জন্য কিছুটা সহজ সংস্করণ জালালাম, নীচে দেখুন।
মাইকে রডেন্ট

4

অনলাইনে আশ্রয় নিয়ে মনে হচ্ছে, জেএনআই দিয়ে এটি করা সম্ভব হতে পারে বলে মনে হচ্ছে। এরপরে আপনাকে সি থেকে পুটেনভ () এ ফোন করতে হবে এবং আপনি (সম্ভবত) উইন্ডোজ এবং ইউএনআইএক্স উভয় ক্ষেত্রে কাজ করে এমনভাবে করতে হবে।

যদি এটি করা যায় তবে জাভা নিজেই আমাকে সোজা জ্যাকেটে রাখার পরিবর্তে এটি সমর্থন করা পক্ষে খুব কঠিন কিছু নয়।

অন্য কোথাও পার্ল-কথা বলার বন্ধু পরামর্শ দেয় যে এটি কারণ পরিবেশের পরিবর্তনশীলগুলি বিশ্বব্যাপী এবং জাভা ভাল ডিজাইনের জন্য ভাল বিচ্ছিন্নতার জন্য চেষ্টা করছে।


হ্যাঁ, আপনি সি কোড থেকে প্রক্রিয়াগুলির পরিবেশ সেট করতে পারেন। তবে জাভাতে কাজ করার বিষয়টি আমি বিবেচনা করব না। প্রারম্ভকালীন সময়ে JVM পরিবেশটি জাভা স্ট্রিং অবজেক্টগুলিতে অনুলিপি করে রাখার একটি ভাল সুযোগ রয়েছে, সুতরাং আপনার পরিবর্তনগুলি ভবিষ্যতে জেভিএম ক্রিয়াকলাপের জন্য ব্যবহৃত হবে না।
ড্যারন

সতর্কতার জন্য ধন্যবাদ, দারন। সম্ভবত আপনি ভাল আছেন একটি ভাল সুযোগ আছে।
skiphoppy

2
@ ড্যারন যে কারণে অনেকগুলি এটি করতে চায় তার জেভিএম মনে করে পরিবেশ কী তা নিয়ে কিছু করার নেই। ( LD_LIBRARY_PATHকল করার আগে সেটিংয়ের কথা ভাবেন Runtime.loadLibrary(); dlopen()কলটি যা জাভির ধারণা হিসাবে নয়, প্রকৃত পরিবেশের দিকে নজর দেয়)।
চার্লস ডাফি

এটি একটি নেটিভ লাইব্রেরি দ্বারা সূচিত উপ-প্রক্রিয়াগুলির জন্য কাজ করে (যা আমার ক্ষেত্রে এটি বেশিরভাগই) তবে দুর্ভাগ্যক্রমে জাভার প্রসেস বা প্রসেসবিল্ডার ক্লাস দ্বারা শুরু হওয়া উপ-প্রক্রিয়াগুলির জন্য কাজ করে না।
ড্যান

4

উপরে পুশির উত্তর চেষ্টা করে এবং এটি বেশিরভাগ অংশের জন্য কাজ করে। তবে, নির্দিষ্ট পরিস্থিতিতে আমি এই ব্যতিক্রমটি দেখতে পাচ্ছি:

java.lang.String cannot be cast to java.lang.ProcessEnvironment$Variable

এই পদ্ধতিটি যখন একাধিকবার বলা হত তখন কিছু অভ্যন্তরীণ শ্রেণীর প্রয়োগের কারণে ProcessEnvironment.যদি setEnv(..)পদ্ধতিটি একাধিকবার বলা হয়, যখন theEnvironmentমানচিত্র থেকে কীগুলি পুনরুদ্ধার করা হয় , সেগুলি এখন স্ট্রিং হয় এর প্রথম অনুরোধের মাধ্যমে স্ট্রিং হিসাবে setEnv(...)) এবং মানচিত্রের জেনেরিক ধরণে কাস্ট করা যায় না, Variable,এটি একটি ব্যক্তিগত অভ্যন্তর শ্রেণিProcessEnvironment.

একটি স্থির সংস্করণ (স্কালায়) নীচে রয়েছে। আশা করি জাভাতে যাওয়া খুব বেশি কঠিন নয়।

def setEnv(newenv: java.util.Map[String, String]): Unit = {
  try {
    val processEnvironmentClass = JavaClass.forName("java.lang.ProcessEnvironment")
    val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
    theEnvironmentField.setAccessible(true)

    val variableClass = JavaClass.forName("java.lang.ProcessEnvironment$Variable")
    val convertToVariable = variableClass.getMethod("valueOf", classOf[java.lang.String])
    convertToVariable.setAccessible(true)

    val valueClass = JavaClass.forName("java.lang.ProcessEnvironment$Value")
    val convertToValue = valueClass.getMethod("valueOf", classOf[java.lang.String])
    convertToValue.setAccessible(true)

    val sampleVariable = convertToVariable.invoke(null, "")
    val sampleValue = convertToValue.invoke(null, "")
    val env = theEnvironmentField.get(null).asInstanceOf[java.util.Map[sampleVariable.type, sampleValue.type]]
    newenv.foreach { case (k, v) => {
        val variable = convertToVariable.invoke(null, k).asInstanceOf[sampleVariable.type]
        val value = convertToValue.invoke(null, v).asInstanceOf[sampleValue.type]
        env.put(variable, value)
      }
    }

    val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
    theCaseInsensitiveEnvironmentField.setAccessible(true)
    val cienv = theCaseInsensitiveEnvironmentField.get(null).asInstanceOf[java.util.Map[String, String]]
    cienv.putAll(newenv);
  }
  catch {
    case e : NoSuchFieldException => {
      try {
        val classes = classOf[java.util.Collections].getDeclaredClasses
        val env = System.getenv()
        classes foreach (cl => {
          if("java.util.Collections$UnmodifiableMap" == cl.getName) {
            val field = cl.getDeclaredField("m")
            field.setAccessible(true)
            val map = field.get(env).asInstanceOf[java.util.Map[String, String]]
            // map.clear() // Not sure why this was in the code. It means we need to set all required environment variables.
            map.putAll(newenv)
          }
        })
      } catch {
        case e2: Exception => e2.printStackTrace()
      }
    }
    case e1: Exception => e1.printStackTrace()
  }
}

জাভাস্লাস কোথায় সংজ্ঞায়িত করা হয়?
মাইক স্লিন

1
সম্ভবত import java.lang.{Class => JavaClass}
র্যান্ডল হুইটম্যান

1
জাভা.লং.প্রসেসইনোমায়ারমেন্ট বাস্তবায়ন এমনকি একই বিল্ডের জন্যও বিভিন্ন প্ল্যাটফর্মে আলাদা। উদাহরণস্বরূপ, জাভা.এলং.প্রসেস-এনভায়রনমেন্ট no উইন্ডোজ প্রয়োগের ক্ষেত্রে কোনও শ্রেণি নেই তবে লিনাক্সের জন্য এই শ্রেণিটি বিদ্যমান। আপনি এটি সহজে পরীক্ষা করতে পারেন। লিনাক্সের জন্য কেবল তার.gz জেডিকে বিতরণ ডাউনলোড করুন এবং src.zip থেকে উত্সটি বের করুন তারপরে এটি উইন্ডোজের বিতরণ থেকে একই ফাইলের সাথে তুলনা করুন। তারা জেডিকে 1.8.0_181 এ সম্পূর্ণ আলাদা। আমি জাভা 10 এ সেগুলি পরীক্ষা করে দেখিনি তবে সেখানে যদি একই চিত্র থাকে তবে আমি অবাক হব না।
অ্যালেক্স কনশিন

1

এটি @ পুশির অশুভ উত্তর =) এর কোটলিন অশুভ সংস্করণ is

@Suppress("UNCHECKED_CAST")
@Throws(Exception::class)
fun setEnv(newenv: Map<String, String>) {
    try {
        val processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment")
        val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
        theEnvironmentField.isAccessible = true
        val env = theEnvironmentField.get(null) as MutableMap<String, String>
        env.putAll(newenv)
        val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
        theCaseInsensitiveEnvironmentField.isAccessible = true
        val cienv = theCaseInsensitiveEnvironmentField.get(null) as MutableMap<String, String>
        cienv.putAll(newenv)
    } catch (e: NoSuchFieldException) {
        val classes = Collections::class.java.getDeclaredClasses()
        val env = System.getenv()
        for (cl in classes) {
            if ("java.util.Collections\$UnmodifiableMap" == cl.getName()) {
                val field = cl.getDeclaredField("m")
                field.setAccessible(true)
                val obj = field.get(env)
                val map = obj as MutableMap<String, String>
                map.clear()
                map.putAll(newenv)
            }
        }
    }

এটি কমপক্ষে ম্যাকোস মোজভেতে কাজ করছে।


0

আপনি যদি স্প্রিংবুট নিয়ে কাজ করেন তবে আপনি নিম্নলিখিত বৈশিষ্ট্যে পরিবেশগত পরিবর্তনশীল নির্দিষ্ট করে যুক্ত করতে পারেন:

was.app.config.properties.toSystemProperties

আপনি কিছু ব্যাখ্যা করতে পারেন?
ফারাজ

0

@ পুশির উত্তরের ভিত্তিতে বৈকল্পিক উইন্ডোতে কাজ করে।

def set_env(newenv):
    from java.lang import Class
    process_environment = Class.forName("java.lang.ProcessEnvironment")
    environment_field =  process_environment.getDeclaredField("theEnvironment")
    environment_field.setAccessible(True)
    env = environment_field.get(None)
    env.putAll(newenv)
    invariant_environment_field = process_environment.getDeclaredField("theCaseInsensitiveEnvironment");
    invariant_environment_field.setAccessible(True)
    invevn = invariant_environment_field.get(None)
    invevn.putAll(newenv)

ব্যবহার:

old_environ = dict(os.environ)
old_environ['EPM_ORACLE_HOME'] = r"E:\Oracle\Middleware\EPMSystem11R1"
set_env(old_environ)

0

টিম রায়ের উত্তর আমার পক্ষে কাজ করেছিল ... তবে আমি এটি গ্রোভির (উদাহরণস্বরূপ স্পোকের প্রসঙ্গে) এবং সরলসিমোতে চেয়েছিলাম:

import java.lang.reflect.Field

def getModifiableEnvironmentMap() {
    def unmodifiableEnv = System.getenv()
    Class cl = unmodifiableEnv.getClass()
    Field field = cl.getDeclaredField("m")
    field.accessible = true
    field.get(unmodifiableEnv)
}

def clearEnvironmentVars( def keys ) {
    def savedVals = [:]
    keys.each{ key ->
        String val = modifiableEnvironmentMap.remove(key)
        // thinking about it, I'm not sure why we need this test for null
        // but haven't yet done any experiments
        if( val != null ) {
            savedVals.put( key, val )
        }
    }
    savedVals
}

def setEnvironmentVars(Map varMap) {
    modifiableEnvironmentMap.putAll(varMap)
}

// pretend existing Env Var doesn't exist
def PATHVal1 = System.env.PATH
println "PATH val1 |$PATHVal1|"
String[] keys = ["PATH", "key2", "key3"]
def savedVars = clearEnvironmentVars(keys)
def PATHVal2 = System.env.PATH
println "PATH val2 |$PATHVal2|"

// return to reality
setEnvironmentVars(savedVars)
def PATHVal3 = System.env.PATH
println "PATH val3 |$PATHVal3|"
println "System.env |$System.env|"

// pretend a non-existent Env Var exists
setEnvironmentVars( [ 'key4' : 'key4Val' ])
println "key4 val |$System.env.key4|"

0

কোটলিনের একটি সংস্করণ, এই অ্যালগরিদমে আমি একটি সজ্জা তৈরি করেছি যা আপনাকে পরিবেশ থেকে ভেরিয়েবলগুলি সেট করতে এবং পেতে সহায়তা করে।

import java.util.Collections
import kotlin.reflect.KProperty

class EnvironmentDelegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return System.getenv(property.name) ?: "-"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        val key = property.name

        val classes: Array<Class<*>> = Collections::class.java.declaredClasses
        val env = System.getenv()

        val cl = classes.first { "java.util.Collections\$UnmodifiableMap" == it.name }

        val field = cl.getDeclaredField("m")
        field.isAccessible = true
        val obj = field[env]
        val map = obj as MutableMap<String, String>
        map.putAll(mapOf(key to value))
    }
}

class KnownProperties {
    var JAVA_HOME: String by EnvironmentDelegate()
    var sample: String by EnvironmentDelegate()
}

fun main() {
    val knowProps = KnownProperties()
    knowProps.sample = "2"

    println("Java Home: ${knowProps.JAVA_HOME}")
    println("Sample: ${knowProps.sample}")
}

-1

কোডলিন বাস্তবায়ন আমি সম্প্রতি এডওয়ার্ডের উত্তরের ভিত্তিতে করেছি:

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)
    }
}

-12

আপনি -D দিয়ে আপনার প্রাথমিক জাভা প্রক্রিয়াতে পরামিতিগুলি পাস করতে পারেন:

java -cp <classpath> -Dkey1=value -Dkey2=value ...

কার্যকর করার সময় মানগুলি জানা যায় না; যখন ব্যবহারকারী তাদের সরবরাহ করে / নির্বাচন করে তাদের প্রোগ্রামের সম্পাদনার সময় তারা পরিচিত হয়। এবং এটি শুধুমাত্র সিস্টেমের বৈশিষ্ট্যগুলি সেট করে, পরিবেশের ভেরিয়েবলগুলি নয়।
skiphoppy

তাহলে সেক্ষেত্রে আপনি সম্ভবত আপনার সাব-প্রসেসেসগুলি চালিত করার জন্য একটি নিয়মিত উপায় (মূল পদ্ধতিতে অর্গস [] প্যারামিটারের মাধ্যমে) সন্ধান করতে চান।
ম্যাট বি বি

ম্যাট বি, নিয়মিত উপায়টি প্রসেসবিল্ডারের মাধ্যমে, যেমনটি আমার মূল প্রশ্নে উল্লেখ করা হয়েছে। :)
skiphoppy

7
-ডি প্যারামিটারগুলির মাধ্যমে উপলব্ধ System.getPropertyএবং এটির মতো নয় System.getenv। এছাড়া Systemবর্গ এছাড়াও ব্যবহার স্ট্যাটিক্যালি এই বৈশিষ্ট্য সেট করতে পারবেনsetProperty
anirvan
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.