Может ли файл свойств 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
Возможно ли это?
Может ли файл свойств 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
Возможно ли это?
Крис Майр XProperties класс может быть хорошей отправной точкой.
Вы можете заменить константу в любом месте значения свойства и даже иметь более одной константы в значении, как в следующем примере:
CONST_1 = shoes and ships
CONST_2 = sealing wax
SomeValue = {CONST_1} and {CONST_2}
В этом примере свойство SomeValue оценивается как "обувь, корабли и сургуч".
Eproperties - это проект с открытым исходным кодом, который обеспечивает замену переменных наряду с несколькими другими функциями, хотя замена может оказаться наиболее полезной. Это подкласс java.util.Properties и может использоваться любым другим классом, который может получать информацию о конфигурации как Свойства.
Также может это сделать Commons Config lib. http://commons.apache.org/configuration/userguide/overview.html#Using_Configuration
Однако, как уже указывалось, взгляните на библиотеку EProperties; http://code.google.com/p/eproperties/
Он поддерживает ряд опрятных функций (таких как подстановка, вложенность, списки), включая включение, расширение свойств Java и немного меньший вес, чем Commons Config (который также позволяет включать свойства с использованием синтаксиса include).
Стандартные файлы свойств - это только пары ключ-значение. В текстовом формате Properties
просто отделяет ключ от значения и выполняет некоторые простые действия, такие как разрешение экранированных символов. Возможно, вы сможете определить объекты в подробном синтаксисе XML.
Если вам нужен собственный синтаксис подстановки, вы можете манипулировать возвращаемым значением, как и с любой другой строкой. Кроме того, вы можете написать свою собственную версию Properties
или выполнить подстановку при создании файла.
Класс java.util.Properties не сделает этого для вас. Было бы не слишком сложно подклассифицировать свойства, переопределить метод load() и самостоятельно выполнить подстановку.
Поскольку свойства eproperties не поддерживаются, а общая конфигурация имеет зависимость от ведения журнала (что по иронии судьбы означает, что вы не можете использовать его для настройки ведения журнала), я использую этот фрагмент кода, который требует только 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
.
В этом конкретном случае (и в других тоже), вам лучше решить дублирование, указав различные свойства:
dir.proj1=dir.default /p1
в dir.proj1_extension=/p1
dir.default
до dir.proj1_extension
, чтобы получить полное местоположение proj1 в вашем коде приложения.Сделайте то же самое для других проектов.
Файл конфигурации состоит из операторов в формате key=value
или key:value
.
Их возможный путь, когда значение ключа может ссылаться на другое значение ключа. Строка между открытием "$ {" и закрытием "}" интерпретируется как ключ. Значение замещенной переменной может быть определено как системное свойство или в самом файле конфигурации.
Поскольку Properties
наследуется от Hashtable
, методы put
и putAll
могут быть применены к Properties object
.
Map<String, String> map = new LinkedHashMap<String, String>();
map.put("key", "vlaue");
Properties props = new Properties();
props.putAll( map );
выработать сообщение @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;
}
}
Файл конфигурации "Если вы хотите, чтобы ссылка была проигнорирована и не будет заменена, вы можете использовать формат ниже.
$${${name}} must be used for output ${ Yash }. EX: jdk = ${jre-1.8}
Файл: 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 (ключ = значение) log4j.properties
Ниже приведен фрагмент кода в 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
.
Ни одно из приведенных решений мне не очень понравилось. EProperties не поддерживается и недоступен в Maven Central. Commons Config слишком велик для этого. 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));
распечатывает:
{машина = это машина из рубена, имя = рубен, другое имя = рубен}
У меня есть вопрос
Я не могу повторно использовать значение ключа для определения другого ключа.
Пример:
alg.Name=claims
${alg.Name}.property1=srcid,extid
${alg.Name}.returnvalue=12
Может ли кто-нибудь предложить какое-нибудь решение или помочь мне в этом?