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
这可能吗?
答案 0 :(得分:51)
这就是你想要的,它有点陈旧,但可能适合你的需要。
Enabling constant substitution in Property Values
您可以在属性值的任何位置替换常量,甚至在值中包含多个常量,如下例所示:
CONST_1 = shoes and ships
CONST_2 = sealing wax
SomeValue = {CONST_1} and {CONST_2}
在此示例中,“SomeValue”属性的评估结果为“鞋子和船只以及封蜡。”
答案 1 :(得分:12)
Eproperties is the open source project提供变量替换以及一些其他功能 - 尽管替换可能是最有用的。它是java.util.Properties的子类,可以被任何其他可以将配置信息作为属性的类使用。
答案 2 :(得分:7)
Commons Config lib也可以这样做。 http://commons.apache.org/configuration/userguide/overview.html#Using_Configuration
但是,正如已经指出的那样,看一下EProperties库; http://code.google.com/p/eproperties/
它支持许多简洁的功能(如替换,嵌套,列表),包括包含,扩展Java属性,并且比Commons Config(它还允许您使用include语法包含属性)更轻一些。
答案 3 :(得分:6)
标准属性文件只是键值对。在文本格式中,Properties
只是将键与值分开,并执行一些简单的操作,例如允许转义字符。您可以使用详细的XML语法定义实体。
如果您需要自己的替换语法,则可以像处理任何其他字符串一样操纵返回的值。或者,您可以编写自己的Properties
版本,或在生成文件时执行替换。
答案 4 :(得分:5)
java.util.Properties类不会为您执行此操作。子类化属性,覆盖load()方法并自己进行替换也不会太困难。
答案 5 :(得分:3)
由于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;
}
<强>输入强>:
blah=${user.dir}
one=1
two=2
five=5
fifteen=${one}${five}
twoonefive=${two}${fifteen}
six=6
<强>输出强>:
blah=/current/working/dir
one=1
two=2
five=5
fifteen=15
twoonefive=215
six=6
显然,如果需要,您可以将Map<String,String>
转换回Properties
对象。我基于先前声明的属性和系统属性来解决,但您显然可以在StrSubstitutor.lookup
。
答案 6 :(得分:1)
在这种特殊情况下(以及others中),您最好通过定义不同的属性来解决重复问题:
dir.proj1=dir.default /p1
更改为dir.proj1_extension=/p1
dir.default
添加到dir.proj1_extension
以获取应用代码中proj1的完整位置。对其他项目也这样做。
答案 7 :(得分:1)
配置文件包含key=value
或key:value
格式的语句。
它们是键值可以引用另一个键值的可能方式。开头“$ {”和结束“}”之间的字符串被解释为键。替换变量的值可以定义为系统属性或配置文件本身。
由于 Properties
继承自 Hashtable
,因此put
和putAll
方法可应用于{ {1}}。
Properties object
详细阐述了 @Adam Gent 的帖子。 commons-text-1.1.jar
Map<String, String> map = new LinkedHashMap<String, String>();
map.put("key", "vlaue");
Properties props = new Properties();
props.putAll( map );
配置文件«如果您想要忽略参考并且不会被替换,那么您可以使用以下格式。
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; } }
档案: $${${name}} must be used for output ${ Yash }. EX: jdk = ${jre-1.8}
keys_ReferedKeys.properties
Java属性(key = value)格式示例log4j.properties
答案 8 :(得分:0)
下面是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);
}
示例属性:
key1=value1
key21=value2 ${key1}
运行此功能后,key21
的值为value2 value1
。
*使用apache的StrSubstitutor
。
答案 9 :(得分:0)
我都不喜欢给定的解决方案。 EProperty未维护,并且在Maven Central中不可用。 Commons Config太大了。 commons-lang中的StrSubstitutor已弃用。
我的解决方案仅依赖于通用文本:
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()));
}
}
即:
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));
打印出:
{car =这是一辆来自鲁本的汽车,name = ruben,another_name = ruben}
答案 10 :(得分:0)
我喜欢上面解决方案的想法,但是我确实想要一些东西来代替Properties。下面的课程基于上面的想法。它仍然使用Apache Commons文本StringSubstitutor,并在Properties类,Java System定义的或System的Env中查找键。此类扩展了Properties并覆盖了getProperty(...)方法,因此是替代品。您可以使用'lookup()'方法获取原始键的值,但是它将从这3个位置之一返回一个值。如果要确定属性中的键是否存在,请使用地图的基础get()。
Apache Commons依赖项:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.3</version>
</dependency>
类源。
import java.util.Properties;
import org.apache.commons.text.StringSubstitutor;
import org.apache.commons.text.lookup.StringLookup;
/**
* This extends Properties to provide macros substitution and includes getting properties from
* the Java System properties or the System's Environment. This could be used to consolidate
* getting a system variable regardless if it is defined in the Java system or in the System's
* environment, without any other actual properties.
*
* The macro substitution is recursive so that given the following properties:
<code>
myProg=Program1
outDir=./target
inputs'./data/${defman }Templates
outputs=${outDir}/${myProg}
log=${outDir}/${myProg}/build_report.txt
homeLog=${HOMEDRIVE}/${log}
</code>
* And assuming the environment variable HOMEDRIVE=C:
* the getProperties("homeLog") would result in: C:/./target/Program1/build_report.txt
*
* Although based on the article below, this version substitutes during the getProperty() functions
* instead of the loading functions explained in the article.
*
* Based on this article:
* https://stackoverflow.com/questions/872272/how-to-reference-another-property-in-java-util-properties
*
* @author Tim Gallagher
* @license - You are free to use, alter etc. for any reason
*/
public class MacroProperties extends Properties implements StringLookup {
// Substitutes variables within a string by values.
public final StringSubstitutor macroSubstiitutor;
public MacroProperties() {
this.macroSubstiitutor = new StringSubstitutor(this);
}
public MacroProperties(Properties prprts) {
super(prprts);
this.macroSubstiitutor = new StringSubstitutor(this);
}
/**
* The value of the key is first searched in the properties, and if not found there, it is then
* searched in the system properties, and if still not found, then it is search in the
* system Env.
*
* @param key non-null string.
* @return may be null.
*/
@Override
public String lookup(String key) {
// get the Property first - this must look up in the parent class
// or we'll get into an endless loop
String value = super.getProperty(key);
if (value == null) {
// if not found, get the Java system property which may have been defined on the
// Java command line with '-D...'
value = System.getProperty(key);
if (value == null) {
// if not found, get the System's environment variable.
value = System.getenv(key);
}
}
return value;
}
@Override
public String getProperty(String key, String defaultValue) {
/*
* 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 = lookup(key);
if (value != null) {
value = macroSubstiitutor.replace(value);
} else {
value = defaultValue;
}
return value;
}
@Override
public String getProperty(String key) {
return getProperty(key, null);
}
}
答案 11 :(得分:0)
“纯”Java 实现:
static final Pattern PATTERN = Pattern.compile("\\$\\{([^}]+)}");
private static void macro(final Properties properties)
{
properties.replaceAll((k, v) -> PATTERN.matcher((String) v).replaceAll(mr -> properties.getProperty(mr.group(1), mr.group(0)).replace("$", "\\$")));
}
可以合并到一个简单的 Properties 子类中,如下所示:
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;
import java.util.regex.Pattern;
public class MacroProperties extends Properties
{
static final Pattern PATTERN = Pattern.compile("\\$\\{([^}]+)}", 0);
@Override
public synchronized void load(final Reader reader) throws IOException
{
super.load(reader);
macro(this);
}
@Override
public synchronized void load(final InputStream inStream) throws IOException
{
super.load(inStream);
macro(this);
}
private static void macro(final Properties properties)
{
properties.replaceAll((k, v) -> PATTERN.matcher((String) v).replaceAll(mr -> properties.getProperty(mr.group(1), mr.group(0)).replace("$", "\\$")));
}
}
它是如何工作的?
PATTERN
是一个匹配简单 ${foo}
模式的正则表达式,并将大括号之间的文本作为一个组捕获。
Properties.replaceAll
应用一个函数来用函数的结果替换每个值。
Matcher.replaceAll
应用一个函数来替换 PATTERN
的每个匹配项。
我们对该函数的实现在属性中查找匹配组 1 或默认为匹配(即实际上不进行替换)。
Matcher.replaceAll
还解释寻找组引用的替换字符串,因此我们还需要使用 String.replace
来反斜杠转义 $
。