private String interpolateBundleMessage( String message, ResourceBundle bundle, Locale locale, boolean recursive) throws MessageDescriptorFormatException { TokenCollector tokenCollector = new TokenCollector(message, InterpolationTermType.PARAMETER); TokenIterator tokenIterator = new TokenIterator(tokenCollector.getTokenList()); while (tokenIterator.hasMoreInterpolationTerms()) { String term = tokenIterator.nextInterpolationTerm(); String resolvedParameterValue = resolveParameter(term, bundle, locale, recursive); tokenIterator.replaceCurrentInterpolationTerm(resolvedParameterValue); } return tokenIterator.getInterpolatedMessage(); }
/** * Runs the message interpolation according to algorithm specified in the Bean Validation * specification. <br> * Note: <br> * Look-ups in user bundles is recursive whereas look-ups in default bundle are not! * * @param message the message to interpolate * @param context the context for this interpolation * @param locale the {@code Locale} to use for the resource bundle. * @return the interpolated message. */ private String interpolateMessage(String message, Context context, Locale locale) throws MessageDescriptorFormatException { LocalizedMessage localisedMessage = new LocalizedMessage(message, locale); String resolvedMessage = null; if (cachingEnabled) { resolvedMessage = resolvedMessages.get(localisedMessage); } // if the message is not already in the cache we have to run step 1-3 of the message resolution if (resolvedMessage == null) { ResourceBundle userResourceBundle = userResourceBundleLocator.getResourceBundle(locale); ResourceBundle defaultResourceBundle = defaultResourceBundleLocator.getResourceBundle(locale); String userBundleResolvedMessage; resolvedMessage = message; boolean evaluatedDefaultBundleOnce = false; do { // search the user bundle recursive (step1) userBundleResolvedMessage = interpolateBundleMessage(resolvedMessage, userResourceBundle, locale, true); // exit condition - we have at least tried to validate against the default bundle and there // was no // further replacements if (evaluatedDefaultBundleOnce && !hasReplacementTakenPlace(userBundleResolvedMessage, resolvedMessage)) { break; } // search the default bundle non recursive (step2) resolvedMessage = interpolateBundleMessage( userBundleResolvedMessage, defaultResourceBundle, locale, false); evaluatedDefaultBundleOnce = true; } while (true); } // cache resolved message if (cachingEnabled) { String cachedResolvedMessage = resolvedMessages.putIfAbsent(localisedMessage, resolvedMessage); if (cachedResolvedMessage != null) { resolvedMessage = cachedResolvedMessage; } } // resolve parameter expressions (step 4) List<Token> tokens = null; if (cachingEnabled) { tokens = tokenizedParameterMessages.get(resolvedMessage); } if (tokens == null) { TokenCollector tokenCollector = new TokenCollector(resolvedMessage, InterpolationTermType.PARAMETER); tokens = tokenCollector.getTokenList(); if (cachingEnabled) { tokenizedParameterMessages.putIfAbsent(resolvedMessage, tokens); } } resolvedMessage = interpolateExpression(new TokenIterator(tokens), context, locale); // resolve EL expressions (step 5) tokens = null; if (cachingEnabled) { tokens = tokenizedELMessages.get(resolvedMessage); } if (tokens == null) { TokenCollector tokenCollector = new TokenCollector(resolvedMessage, InterpolationTermType.EL); tokens = tokenCollector.getTokenList(); if (cachingEnabled) { tokenizedELMessages.putIfAbsent(resolvedMessage, tokens); } } resolvedMessage = interpolateExpression(new TokenIterator(tokens), context, locale); // last but not least we have to take care of escaped literals resolvedMessage = replaceEscapedLiterals(resolvedMessage); return resolvedMessage; }