如何在 java.util.Properties 中引用另一个属性?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/872272/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:30:14  来源:igfitidea点击:

How to reference another property in java.util.Properties?

javaproperties

提问by yli

Can Java properties file reference other properties file?

Java 属性文件可以引用其他属性文件吗?

## define a default directory for Input files  
dir.default=/home/data/in/

dir.proj1=${dir.default}p1
dir.proj2=${dir.default}p2
dir.proj3=${dir.default}p3

Is this possible?

这可能吗?

回答by highlycaffeinated

The java.util.Properties class won't do this for you. It wouldn't be too difficult to subclass Properties, override the load() method and do the substitution yourself.

java.util.Properties 类不会为您执行此操作。对 Properties 进行子类化,覆盖 load() 方法并自己进行替换并不会太困难。

回答by Tom Hawtin - tackline

Standard properties files are just key-value pairs. In the text format, Propertiesjust separates key from value and does some simple things such as allowing escaped characters. You might be able to define entities in the verbose XML syntax.

标准属性文件只是键值对。在文本格式中,Properties只是将键与值分开并做一些简单的事情,例如允许转义字符。您或许能够以详细的 XML 语法定义实体。

If you want your own substitution syntax, then you can manipulate a returned value as you would with any other string. Alternatively, you could write your own version of Propertiesor do the substitution when generating the file.

如果您想要自己的替换语法,那么您可以像处理任何其他字符串一样操作返回值。或者,您可以Properties在生成文件时编写自己的版本或进行替换。

回答by Paul

Eproperties is the open source projectwhich provides variable substitution along with a few other features - although substitution may arguably be the most useful. It is a subclass of java.util.Properties, and will can be used by any other class that may take configuration information as Properties.

Eproperties 是一个开源项目,它提供变量替换以及一些其他功能——尽管替换可能是最有用的。它是 java.util.Properties 的子类,并且可以被任何其他可能将配置信息作为属性的类使用。

回答by OscarRyz

Chris Mair's XPropertiesclass may be a good starting point.

Chris Mair 的XProperties类可能是一个很好的起点。

You can substitute a constant anywhere in the property value, and even have more than one constant within a value, as in the following example:

您可以在属性值的任何位置替换常量,甚至可以在一个值中包含多个常量,如下例所示:

CONST_1 = shoes and ships
CONST_2 = sealing wax
SomeValue = {CONST_1} and {CONST_2} 

In this example, the "SomeValue" property evaluates to "shoes and ships and sealing wax."

在此示例中,“SomeValue”属性的计算结果为“鞋子和船和密封蜡”。



See also: http://webcache.googleusercontent.com/search?q=cache:gCgFCpEgmsgJ:www2.sys-con.com/itsg/virtualcd/java/source/6-12/52.html+&cd=1&hl=en&ct=clnk&gl=us

另见:http: //webcache.googleusercontent.com/search?q=cache: gCgFCpEgmsgJ: www2.sys-con.com/itsg/virtualcd/java/source/6-12/52.html+&cd=1&hl=en&ct =clnk&gl=我们

回答by The Nail

In this particular case (and in otherstoo), you'd better resolve the duplication by defining different properties:

在这种特殊情况下(以及在其他情况下),您最好通过定义不同的属性来解决重复问题:

  1. change: dir.proj1=dir.default /p1into dir.proj1_extension=/p1
  2. prepend: dir.defaultto dir.proj1_extensionto get the full location of proj1 in your application code.
  1. 改变:dir.proj1=dir.default /p1变成dir.proj1_extension=/p1
  2. prepend: dir.defaulttodir.proj1_extension在您的应用程序代码中获取 proj1 的完整位置。

Do the same for the other projects.

对其他项目做同样的事情。

回答by NightWolf

The Commons Config lib can also do this. http://commons.apache.org/configuration/userguide/overview.html#Using_Configuration

Commons Config lib 也可以做到这一点。http://commons.apache.org/configuration/userguide/overview.html#Using_Configuration

However, as pointed out already, have a look at the EProperties library; http://code.google.com/p/eproperties/

但是,正如已经指出的,请查看 EProperties 库;http://code.google.com/p/eproperties/

It supports a number of neat features (like substitution, nesting, lists) including inclusion, extends Java Properties and is a little more light weight than Commons Config (which also allows you to include properties using the include syntax).

它支持许多简洁的功能(如替换、嵌套、列表),包括包含、扩展 Java 属性,并且比 Commons Config 轻一些(它还允许您使用包含语法包含属性)。

回答by Adam Gent

Since eproperties is sort of not maintained and commons configuration has a dependency on logging (which ironically means you can't use it to configure logging) I use this code snippet which only requires commons-lang(3)to load interpolated properties:

由于 eproperties 没有维护,并且 commons 配置依赖于日志记录(具有讽刺意味的是,这意味着您不能使用它来配置日志记录)我使用这个代码片段,它只需要commons-lang(3)加载插入的属性:

@SuppressWarnings("serial")
public static Map<String,String> loadPropertiesMap(InputStream s) throws IOException {
    final Map<String, String> ordered = new LinkedHashMap<String, String>();
    //Hack to use properties class to parse but our map for preserved order
    Properties bp = new Properties() {
        @Override
        public synchronized Object put(Object key, Object value) {
            ordered.put((String)key, (String)value);
            return super.put(key, value);
        }
    };
    bp.load(s);
    final Map<String,String> resolved = new LinkedHashMap<String, String>(ordered.size());
    StrSubstitutor sub = new StrSubstitutor(new StrLookup<String>() {
        @Override
        public String lookup(String key) {
            String value = resolved.get(key);
            if (value == null)
                return System.getProperty(key);
            return value;
        }
    });
    for (String k : ordered.keySet()) {
        String value = sub.replace(ordered.get(k));
        resolved.put(k, value);
    }
    return resolved;
}

Input:

输入

blah=${user.dir}
one=1
two=2
five=5
fifteen=${one}${five}
twoonefive=${two}${fifteen}
six=6

Output:

输出

blah=/current/working/dir
one=1
two=2
five=5
fifteen=15
twoonefive=215
six=6

Obviously you can convert the Map<String,String>back to a Propertiesobject if you need it. I resolve based on previously declared properties and system properties but you could obviously adjust that in the StrSubstitutor.lookup.

显然,如果需要,您可以将Map<String,String>返回转换为Properties对象。我根据先前声明的属性和系统属性进行解析,但您显然可以在StrSubstitutor.lookup.

回答by AlikElzin-kilaka

Below is a code snippet in Java for reading properties that reference other properties. Specifically, these are are reusable queries but can be other stuff as well.

下面是 Java 中的代码片段,用于读取引用其他属性的属性。具体来说,这些是可重用的查询,但也可以是其他内容。

LinkedHashMap<String, String> sqlsRaw = loadPropertiesFromFile();
LinkedHashMap<String, String> sqls = new LinkedHashMap<>();
StrSubstitutor substitutor = new StrSubstitutor(sqls);

for (Map.Entry<String, String> entry : sqlsRaw.entrySet()) {
    String sql = entry.getValue();
    try {
        sql = substitutor.replace(sql);
    } catch (Exception e) {
        throw new RuntimeException("Found an sql with a non replaced reference to another. Please validate that the required key was defined before this sql: " + entry.getValue(), e);
    }
    sqls.put(entry.getKey(), sql);
}

Example properties:

示例属性:

key1=value1
key21=value2 ${key1}

After running this, key21will have the value value2 value1.

运行此后,key21将具有值value2 value1

* Using apache's StrSubstitutor.

* 使用 apache 的StrSubstitutor.

回答by Yash

The configuration file consists of statements in the format key=valueor key:value. Their are possible way where a key value can refer the another key value. The string between an opening "${"and closing "}"is interpreted as a key. The value of the substituted variable can be defined as a system property or in the configuration file itself.

配置文件由格式为key=valueor的语句组成key:value。它们是一个键值可以引用另一个键值的可能方式。开头“${”和结尾“}”之间的字符串被解释为键。替换变量的值可以定义为系统属性或配置文件本身。

Because Propertiesinherits from Hashtable, theputand putAllmethods can be applied to a Properties object.

因为Properties继承自Hashtable,所以putputAll方法可以应用于Properties object.

Map<String, String> map = new LinkedHashMap<String, String>();
map.put("key", "vlaue");
Properties props = new Properties();
props.putAll( map );

elaborating the post of @Adam Gentin-detailed. commons-text-1.1.jar

详细阐述@Adam Gent的帖子。commons-text-1.1.jar

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

public class Properties_With_ReferedKeys {
    public static void main(String[] args) {

        ClassLoader classLoader = Properties_With_ReferedKeys.class.getClassLoader();

        String propertiesFilename = "keys_ReferedKeys.properties";
        Properties props = getMappedProperties(classLoader, propertiesFilename);

        System.out.println( props.getProperty("jdk") );

    }


    public static Properties getMappedProperties( ClassLoader classLoader, String configFilename ) {
        Properties fileProperties = new Properties();

        try {
            InputStream resourceAsStream = classLoader.getResourceAsStream( configFilename );

            Map<String, String> loadPropertiesMap = loadPropertiesMap( resourceAsStream );
            Set<String> keySet = loadPropertiesMap.keySet();
            System.out.println("Provided 'Key':'Value' pairs are...");
            for (String key : keySet) {
                System.out.println( key + " : " + loadPropertiesMap.get(key) );
            }

            fileProperties.putAll( loadPropertiesMap );
        } catch ( IOException e ) {
            e.printStackTrace();
        }

        return fileProperties;
    }
    public static Map<String,String> loadPropertiesMap( InputStream inputStream ) throws IOException {
        final Map<String, String> unResolvedProps = new LinkedHashMap<String, String>();

        /*Reads a property list (key and element pairs) from the input byte stream. 
         * The input stream is in a simple line-oriented format.
         */
        @SuppressWarnings("serial")
        Properties props = new Properties() {
            @Override
            public synchronized Object put(Object key, Object value) {
                unResolvedProps.put( (String)key, (String)value );
                return super.put( key, value );
            }
        };
        props.load( inputStream );

        final Map<String,String> resolvedProps = new LinkedHashMap<String, String>( unResolvedProps.size() );

        // Substitutes variables within a string by values.
        StrSubstitutor sub = new StrSubstitutor( new StrLookup<String>() {
            @Override
            public String lookup( String key ) {

                /*The value of the key is first searched in the configuration file,
                 * and if not found there, it is then searched in the system properties.*/
                String value = resolvedProps.get( key );

                if (value == null)
                    return System.getProperty( key );

                return value;
            }
        } );

        for ( String key : unResolvedProps.keySet() ) {

            /*Replaces all the occurrences of variables with their matching values from the resolver using the given 
             * source string as a template. By using the default ${} the corresponding value replaces the ${variableName} sequence.*/
            String value = sub.replace( unResolvedProps.get( key ) );
            resolvedProps.put( key, value );
        }
        return resolvedProps;
    }
}

Configuration File ? If you want reference to be ignored and won't be replaced then you can use below format.

 $${${name}} must be used for output ${ Yash }.  EX: jdk = ${jre-1.8}

配置文件?如果您希望引用被忽略并且不会被替换,那么您可以使用以下格式。

 $${${name}} must be used for output ${ Yash }.  EX: jdk = ${jre-1.8}

File: keys_ReferedKeys.properties

文件: keys_ReferedKeys.properties

# MySQL Key for each developer for their local machine
dbIP       = 127.0.0.1
dbName     = myApplicationDB
dbUser     = scott
dbPassword = tiger

# MySQL Properties 
# To replace fixed-keys with corresponding build environment values. like ? predev,testing,preprd.
config.db.driverClassName : com.mysql.jdbc.Driver
config.db.url             : jdbc:mysql://${dbIP}:3306/${dbName}
config.db.username        : ${dbUser}
config.db.password        : ${dbPassword}

# SystemProperties
userDir      = ${user.dir}
os.name      = ${os.name}
java.version = ${java.version}
java.specification.version = ${java.specification.version}

# If you want reference to be ignored and won't be replaced.
# $${${name}} must be used for output ${ Yash }.  EX: jdk = ${jre-1.8}
jdk = $${jre-${java.specification.version}}


Java properties (key=value) format example log4j.properties

Java 属性(键=值)格式示例log4j.properties

回答by lqbweb

None of the given solutions I really liked. EProperties is not maintained, and it is not available in Maven Central. Commons Config is too big for this. StrSubstitutor in commons-lang is deprecated.

没有一个给定的解决方案我真的很喜欢。EProperties 没有维护,它在 Maven Central 中不可用。Commons Config 对于这个来说太大了。commons-lang 中的 StrSubstitutor 已弃用。

My solution just relies on common-text:

我的解决方案仅依赖于通用文本:

public static Properties interpolateProperties(Properties rawProperties) {
    Properties newProperties = new Properties();
    interpolateProperties(rawProperties, newProperties);
    return newProperties;
}

public static void interpolateProperties(Properties rawProperties, Properties dstProperties) {
    StringSubstitutor sub = new StringSubstitutor((Map)rawProperties);
    for (Map.Entry<Object, Object> e : rawProperties.entrySet()) {
        dstProperties.put(e.getKey(), sub.replace(e.getValue()));
    }
}

ie:

IE:

Properties props = new Properties();
props.put("another_name", "lqbweb");
props.put("car", "this is a car from ${name}");
props.put("name", "${another_name}");
System.out.println(interpolateProperties(props));

prints out:

打印出来:

{car=this is a car from ruben, name=ruben, another_name=ruben}

{car=这是来自鲁本的汽车,名称=鲁本,another_name=鲁本}