in spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/SystemPropertyUtils.java [91:142]
private static String parseStringValue(Properties properties, String value, String current,
Set<String> visitedPlaceholders) {
StringBuilder buf = new StringBuilder(current);
int startIndex = current.indexOf(PLACEHOLDER_PREFIX);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(buf, startIndex);
if (endIndex != -1) {
String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
String originalPlaceholder = placeholder;
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
// Recursive invocation, parsing placeholders contained in the
// placeholder
// key.
placeholder = parseStringValue(properties, value, placeholder, visitedPlaceholders);
// Now obtain the value for the fully resolved key...
String propVal = resolvePlaceholder(properties, value, placeholder);
if (propVal == null) {
int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + VALUE_SEPARATOR.length());
propVal = resolvePlaceholder(properties, value, actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
propVal = parseStringValue(properties, value, propVal, visitedPlaceholders);
buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
startIndex = buf.indexOf(PLACEHOLDER_PREFIX, startIndex + propVal.length());
}
else {
// Proceed with unprocessed value.
startIndex = buf.indexOf(PLACEHOLDER_PREFIX, endIndex + PLACEHOLDER_SUFFIX.length());
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}
return buf.toString();
}