jodd-props/src/main/java/jodd/props/PropsData.java
public String resolveMacros(String value, final String... profiles) {
		// create string template parser that will be used internally
		StringTemplateParser stringTemplateParser = new StringTemplateParser();
		stringTemplateParser.setResolveEscapes(false);

		if (!ignoreMissingMacros) {
			stringTemplateParser.setReplaceMissingKey(false);
		} else {
			stringTemplateParser.setReplaceMissingKey(true);
			stringTemplateParser.setMissingKeyReplacement(StringPool.EMPTY);
		}

		final Function<String, String> macroResolver = macroName -> {
			String[] lookupProfiles = profiles;

			int leftIndex = macroName.indexOf('<');
			if (leftIndex != -1) {
				int rightIndex = macroName.indexOf('>');

				String profiles1 = macroName.substring(leftIndex + 1, rightIndex);
				macroName = macroName.substring(0, leftIndex).concat(macroName.substring(rightIndex + 1));

				lookupProfiles = StringUtil.splitc(profiles1, ',');

				StringUtil.trimAll(lookupProfiles);
			}

			return lookupValue(macroName, lookupProfiles);
		};

		// start parsing
		int loopCount = 0;

		while (loopCount++ < MAX_INNER_MACROS) {
			final String newValue = stringTemplateParser.parse(value, macroResolver);

			if (newValue.equals(value)) {
				break;
			}

			if (skipEmptyProps) {
				if (newValue.length() == 0) {
					return null;
				}
			}

			value = newValue;
		}

		return value;
	}
public String resolveMacros(String value, final String... profiles) {
		// create string template parser that will be used internally
		StringTemplateParser stringTemplateParser = new StringTemplateParser();
		stringTemplateParser.setResolveEscapes(false);

		if (!ignoreMissingMacros) {
			stringTemplateParser.setReplaceMissingKey(false);
		} else {
			stringTemplateParser.setReplaceMissingKey(true);
			stringTemplateParser.setMissingKeyReplacement(StringPool.EMPTY);
		}

		final Function<String, String> macroResolver = macroName -> {
			String[] lookupProfiles = profiles;

			int leftIndex = macroName.indexOf('<');
			if (leftIndex != -1) {
				int rightIndex = macroName.indexOf('>');

				String profiles1 = macroName.substring(leftIndex + 1, rightIndex);
				macroName = macroName.substring(0, leftIndex).concat(macroName.substring(rightIndex + 1));

				lookupProfiles = StringUtil.splitc(profiles1, ',');

				StringUtil.trimAll(lookupProfiles);
			}

			return lookupValue(macroName, lookupProfiles);
		};

		// start parsing
		int loopCount = 0;

		while (loopCount++ < MAX_INNER_MACROS) {
			final String newValue = stringTemplateParser.parse(value, macroResolver);

			if (newValue.equals(value)) {
				break;
			}

			if (skipEmptyProps) {
				if (newValue.length() == 0) {
					return null;
				}
			}

			value = newValue;
		}

		return value;
	}
Resolves all macros in this props set. Called on property lookup.