Ravat Tailor
Ravat Tailor

Reputation: 1263

Jenkins throw java.lang.NoSuchFieldException: theCaseInsensitiveEnvironment

I am trying to set environment variable through a unit test, when I am running my code on the local machine it is working fine.

But when I deploying it on Jenkins pipeline it starts throwing an exception.

Exception :-

java.lang.NoSuchFieldException: theCaseInsensitiveEnvironment

Code snippet :-

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

Upvotes: 0

Views: 1744

Answers (2)

Intenex
Intenex

Reputation: 1947

That field probably doesn't exist on your java.lang.ProcessEnvironment class.

A quick check should show you all the actual fields you have access to:

Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
for (Field field : processEnvironmentClass.getDeclaredFields()) {
    System.out.print(field.getName() + "\n");
}

In my case, I ran into the same error, and quickly discovered the only fields my ProcessEnvironment has are the following:

theEnvironment
theUnmodifiableEnvironment
MIN_NAME_LENGTH

My best understanding is that theEnvironment has replaced theCaseInsensitiveEnvironment, and what you actually want to also replace is theUnmodifiableEnvironment, so that your code reads like so:

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 theUnmodifiableEnvironmentField = processEnvironmentClass.getDeclaredField("theUnmodifiableEnvironment");
theUnmodifiableEnvironmentField.setAccessible(true);
Map<String, String> umenv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
umenv.clear();
umenv.putAll(newenv);

I'm assuming you're following something like https://sites.google.com/site/androcoding/classroom-news/howtosetenvironmentparametersusingjava from 2012, and our ProcessEnvironment class is just different in the version of Java we're using now in what fields it has.

Upvotes: -1

Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 299148

You're fixing the wrong problem. Your business code should never directly depend on environment variable, there should be an isolation layer in between. Decouple your input from your service code, and you will no longer need to mock environment variables.

Upvotes: 2

Related Questions