📄 abstractmessagesource.java
字号:
* @see #getMessage(MessageSourceResolvable, Locale)
* @see #setUseCodeAsDefaultMessage
*/
protected String getMessageInternal(String code, Object[] args, Locale locale) {
if (code == null) {
return null;
}
if (locale == null) {
locale = Locale.getDefault();
}
if (!isAlwaysUseMessageFormat() && ObjectUtils.isEmpty(args)) {
// Optimized resolution: no arguments to apply,
// therefore no MessageFormat needs to be involved.
// Note that the default implementation still uses MessageFormat;
// this can be overridden in specific subclasses.
String message = resolveCodeWithoutArguments(code, locale);
if (message != null) {
return message;
}
}
else {
MessageFormat messageFormat = resolveCode(code, locale);
if (messageFormat != null) {
synchronized (messageFormat) {
return messageFormat.format(resolveArguments(args, locale));
}
}
}
// Not found -> check parent, if any.
return getMessageFromParent(code, args, locale);
}
/**
* Try to retrieve the given message from the parent MessageSource, if any.
* @param code the code to lookup up, such as 'calculator.noRateSet'
* @param args array of arguments that will be filled in for params
* within the message
* @param locale the Locale in which to do the lookup
* @return the resolved message, or <code>null</code> if not found
* @see #getParentMessageSource()
*/
protected String getMessageFromParent(String code, Object[] args, Locale locale) {
MessageSource parent = getParentMessageSource();
if (parent != null) {
if (parent instanceof AbstractMessageSource) {
// Call internal method to avoid getting the default code back
// in case of "useCodeAsDefaultMessage" being activated.
return ((AbstractMessageSource) parent).getMessageInternal(code, args, locale);
}
else {
// Check parent MessageSource, returning null if not found there.
return parent.getMessage(code, args, null, locale);
}
}
// Not found in parent either.
return null;
}
/**
* Return a fallback default message for the given code, if any.
* <p>Default is to return the code itself if "useCodeAsDefaultMessage"
* is activated, or return no fallback else. In case of no fallback,
* the caller will usually receive a NoSuchMessageException from
* <code>getMessage</code>.
* @param code the message code that we couldn't resolve
* and that we didn't receive an explicit default message for
* @return the default message to use, or <code>null</code> if none
* @see #setUseCodeAsDefaultMessage
*/
protected String getDefaultMessage(String code) {
if (isUseCodeAsDefaultMessage()) {
return code;
}
return null;
}
/**
* Render the given default message String. The default message is
* passed in as specified by the caller and can be rendered into
* a fully formatted default message shown to the user.
* <p>Default implementation passes the String to <code>formatMessage</code>,
* resolving any argument placeholders found in them. Subclasses may override
* this method to plug in custom processing of default messages.
* @param defaultMessage the passed-in default message String
* @param args array of arguments that will be filled in for params within
* the message, or <code>null</code> if none.
* @param locale the Locale used for formatting
* @return the rendered default message (with resolved arguments)
* @see #formatMessage(String, Object[], java.util.Locale)
*/
protected String renderDefaultMessage(String defaultMessage, Object[] args, Locale locale) {
return formatMessage(defaultMessage, args, locale);
}
/**
* Format the given message String, using cached MessageFormats.
* By default invoked for passed-in default messages, to resolve
* any argument placeholders found in them.
* @param msg the message to format
* @param args array of arguments that will be filled in for params within
* the message, or <code>null</code> if none.
* @param locale the Locale used for formatting
* @return the formatted message (with resolved arguments)
*/
protected String formatMessage(String msg, Object[] args, Locale locale) {
if (msg == null || (!this.alwaysUseMessageFormat && (args == null || args.length == 0))) {
return msg;
}
MessageFormat messageFormat = null;
synchronized (this.cachedMessageFormats) {
messageFormat = (MessageFormat) this.cachedMessageFormats.get(msg);
if (messageFormat == null) {
messageFormat = createMessageFormat(msg, locale);
this.cachedMessageFormats.put(msg, messageFormat);
}
}
synchronized (messageFormat) {
return messageFormat.format(resolveArguments(args, locale));
}
}
/**
* Create a MessageFormat for the given message and Locale.
* <p>This implementation creates an empty MessageFormat first,
* populating it with Locale and pattern afterwards, to stay
* compatible with J2SE 1.3.
* @param msg the message to create a MessageFormat for
* @param locale the Locale to create a MessageFormat for
* @return the MessageFormat instance
*/
protected MessageFormat createMessageFormat(String msg, Locale locale) {
if (logger.isDebugEnabled()) {
logger.debug("Creating MessageFormat for pattern [" + msg + "] and locale '" + locale + "'");
}
MessageFormat messageFormat = new MessageFormat("");
messageFormat.setLocale(locale);
if (msg != null) {
messageFormat.applyPattern(msg);
}
return messageFormat;
}
/**
* Search through the given array of objects, find any
* MessageSourceResolvable objects and resolve them.
* <p>Allows for messages to have MessageSourceResolvables as arguments.
* @param args array of arguments for a message
* @param locale the locale to resolve through
* @return an array of arguments with any MessageSourceResolvables resolved
*/
protected Object[] resolveArguments(Object[] args, Locale locale) {
if (args == null) {
return new Object[0];
}
List resolvedArgs = new ArrayList(args.length);
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof MessageSourceResolvable) {
resolvedArgs.add(getMessage((MessageSourceResolvable) args[i], locale));
}
else {
resolvedArgs.add(args[i]);
}
}
return resolvedArgs.toArray(new Object[resolvedArgs.size()]);
}
/**
* Subclasses can override this method to resolve a message without
* arguments in an optimized fashion, i.e. to resolve a message
* without involving a MessageFormat.
* <p>The default implementation <i>does</i> use MessageFormat,
* through delegating to the <code>resolveCode</code> method.
* Subclasses are encouraged to replace this with optimized resolution.
* <p>Unfortunately, <code>java.text.MessageFormat</code> is not
* implemented in an efficient fashion. In particular, it does not
* detect that a message pattern doesn't contain argument placeholders
* in the first place. Therefore, it's advisable to circumvent
* MessageFormat completely for messages without arguments.
* @param code the code of the message to resolve
* @param locale the Locale to resolve the code for
* (subclasses are encouraged to support internationalization)
* @return the message String, or <code>null</code> if not found
* @see #resolveCode
* @see java.text.MessageFormat
*/
protected String resolveCodeWithoutArguments(String code, Locale locale) {
MessageFormat messageFormat = resolveCode(code, locale);
if (messageFormat != null) {
synchronized (messageFormat) {
return messageFormat.format(new Object[0]);
}
}
return null;
}
/**
* Subclasses must implement this method to resolve a message.
* <p>Returns a MessageFormat instance rather than a message String,
* to allow for appropriate caching of MessageFormats in subclasses.
* <p><b>Subclasses are encouraged to provide optimized resolution
* for messages without arguments, not involving MessageFormat.</b>
* See <code>resolveCodeWithoutArguments</code> javadoc for details.
* @param code the code of the message to resolve
* @param locale the Locale to resolve the code for
* (subclasses are encouraged to support internationalization)
* @return the MessageFormat for the message, or <code>null</code> if not found
* @see #resolveCodeWithoutArguments(String, java.util.Locale)
*/
protected abstract MessageFormat resolveCode(String code, Locale locale);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -