Interpolating environment variables in string
Asked Answered
J

3

3

I need to expand environment variables in a string. For example, when parsing a config file, I want to be able to read this...

statsFile=${APP_LOG_DIR}/app.stats

And get a value of "/logs/myapp/app.stats", where the environment variable APP_LOG_DIR = "/logs/myapp".

This seems like a very common need, and things like the Logback framework do this for their own config files, but I have not found a canonical way of doing this for my own config files.

Notes:

  1. This is not a duplicate of the many "variable interpolation in java strings" questions. I need to interpolate environment variables in the specific format ${ENV_VAR}.

  2. The same question was asked here, Expand env variables in String, but the answer requires the Spring framework, and I don't want to pull in this huge dependency just to do this one simple task.

  3. Other languages, like go, have a simple built-in function for this: Interpolate a string with bash-like environment variables references. I am looking for something similar in java.

Joachima answered 8/11, 2019 at 16:25 Comment(4)
The variable APP_LOG_DIR is an environment variable or a property within your configuration file?Herbert
APP_LOG_DIR is an environment variable that I want to reference in my config file with the use of the ${APP_LOG_DIR} syntax.Joachima
What about this one: #4753317Symphysis
@radulfr, that looks similar to what I need. For such a common requirement, I was thinking there would be a solution that didn't require writing my own function, but this may work if I can't find a better way.Joachima
J
2

Answering my own question. Thanks to clues from @radulfr's link in the comments above to Expand environment variables in text, I found a pretty clean solution, using StrSubstitutor, here: https://dkbalachandar.wordpress.com/2017/10/13/how-to-use-strsubstitutor/

To summarize:

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.StrLookup;
import org.apache.commons.lang3.text.StrSubstitutor;

public class StrSubstitutorMain {

    private static final StrSubstitutor envPropertyResolver = new StrSubstitutor(new EnvLookUp());

    public static void main(String[] args) {

        String sample = "LANG: ${LANG}";
        //LANG: en_US.UTF-8
        System.out.println(envPropertyResolver.replace(sample));

    }

    private static class EnvLookUp extends StrLookup {

        @Override
        public String lookup(String key) {
            String value = System.getenv(key);
            if (StringUtils.isBlank(value)) {
                throw new IllegalArgumentException("key" + key + "is not found in the env variables");
            }
            return value;
        }
    }
}
Joachima answered 8/11, 2019 at 18:48 Comment(0)
C
2

as of 2022, both StrLookup and StrSubstitutor are deprecated

so I update @sagebrush’s answer:

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lookup.StringLookup;
import org.apache.commons.text.StringSubstitutor;

public class StrSubstitutorMain {

    private static final StringSubstitutor envPropertyResolver = new StringSubstitutor(new EnvLookUp());

    public static void main(String[] args) {

        String sample = "LANG: ${LANG}";
        //LANG: en_US.UTF-8
        System.out.println(envPropertyResolver.replace(sample));

    }

    private static class EnvLookUp implements StringLookup {

        @Override
        public String lookup(String key) {
            String value = System.getenv(key);
            if (StringUtils.isBlank(value)) {
                throw new IllegalArgumentException("key" + key + "is not found in the env variables");
            }
            return value;
        }
    }
}
Cosmic answered 29/11, 2022 at 9:43 Comment(0)
S
0

You can use Java's String Templates feature. It is described in JEP 430, and it appears in JDK 21 as a preview feature. Here is an example use:

String name = "Joan";
String info = STR."My name is \{name}";
assert info.equals("My name is Joan");   // true

Java's string templates are more versatile, and much safer, than features in other languagues such as C#'s string interpolation and Python's f-strings. For example, string concatenation or interpolation makes SQL injection attacks possible:

String query = "SELECT * FROM Person p WHERE p.last_name = '" + name + "'";
ResultSet rs = conn.createStatement().executeQuery(query);

but this variant (from JEP 430) prevents SQL injection:

PreparedStatement ps = DB."SELECT * FROM Person p WHERE p.last_name = \{name}";
ResultSet rs = ps.executeQuery();

and you could have a similar string template that avoids JavaScript injection attacks.

Selfeducated answered 4/8, 2023 at 22:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.