interface,
implementing common handling of message variants, making it easy
to implement a specific strategy for a concrete MessageSource.
Supports not only MessageSourceResolvables as primary messages
but also resolution of message arguments that are in turn
MessageSourceResolvables themselves.
This class does not implement caching of messages per code, thus
subclasses can dynamically change messages over time. Subclasses are
encouraged to cache their messages in a modification-aware fashion,
allowing for hot deployment of updated messages.
| Method from org.springframework.context.support.AbstractMessageSource Detail: |
protected String getDefaultMessage(String code) {
if (isUseCodeAsDefaultMessage()) {
return code;
}
return null;
}
Return a fallback default message for the given code, if any.
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
getMessage. |
public final String getMessage(MessageSourceResolvable resolvable,
Locale locale) throws NoSuchMessageException {
String[] codes = resolvable.getCodes();
if (codes == null) {
codes = new String[0];
}
for (int i = 0; i < codes.length; i++) {
String msg = getMessageInternal(codes[i], resolvable.getArguments(), locale);
if (msg != null) {
return msg;
}
}
if (resolvable.getDefaultMessage() != null) {
return renderDefaultMessage(resolvable.getDefaultMessage(), resolvable.getArguments(), locale);
}
if (codes.length > 0) {
String fallback = getDefaultMessage(codes[0]);
if (fallback != null) {
return fallback;
}
}
throw new NoSuchMessageException(codes.length > 0 ? codes[codes.length - 1] : null, locale);
}
|
public final String getMessage(String code,
Object[] args,
Locale locale) throws NoSuchMessageException {
String msg = getMessageInternal(code, args, locale);
if (msg != null) {
return msg;
}
String fallback = getDefaultMessage(code);
if (fallback != null) {
return fallback;
}
throw new NoSuchMessageException(code, locale);
}
|
public final String getMessage(String code,
Object[] args,
String defaultMessage,
Locale locale) {
String msg = getMessageInternal(code, args, locale);
if (msg != null) {
return msg;
}
if (defaultMessage == null) {
String fallback = getDefaultMessage(code);
if (fallback != null) {
return fallback;
}
}
return renderDefaultMessage(defaultMessage, args, locale);
}
|
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;
}
Try to retrieve the given message from the parent MessageSource, if any. |
protected String getMessageInternal(String code,
Object[] args,
Locale locale) {
if (code == null) {
return null;
}
if (locale == null) {
locale = Locale.getDefault();
}
Object[] argsToUse = args;
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 {
// Resolve arguments eagerly, for the case where the message
// is defined in a parent MessageSource but resolvable arguments
// are defined in the child MessageSource.
argsToUse = resolveArguments(args, locale);
MessageFormat messageFormat = resolveCode(code, locale);
if (messageFormat != null) {
synchronized (messageFormat) {
return messageFormat.format(argsToUse);
}
}
}
// Not found - > check parent, if any.
return getMessageFromParent(code, argsToUse, locale);
}
Resolve the given code and arguments as message in the given Locale,
returning null if not found. Does not fall back to
the code as default message. Invoked by getMessage methods. |
public MessageSource getParentMessageSource() {
return this.parentMessageSource;
}
|
protected boolean isUseCodeAsDefaultMessage() {
return this.useCodeAsDefaultMessage;
}
Return whether to use the message code as default message instead of
throwing a NoSuchMessageException. Useful for development and debugging.
Default is "false".
Alternatively, consider overriding the getDefaultMessage
method to return a custom fallback message for an unresolvable code. |
protected String renderDefaultMessage(String defaultMessage,
Object[] args,
Locale locale) {
return formatMessage(defaultMessage, args, locale);
}
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.
The default implementation passes the String to formatMessage,
resolving any argument placeholders found in them. Subclasses may override
this method to plug in custom processing of default messages. |
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()]);
}
|
abstract protected MessageFormat resolveCode(String code,
Locale locale)
Subclasses must implement this method to resolve a message.
Returns a MessageFormat instance rather than a message String,
to allow for appropriate caching of MessageFormats in subclasses.
Subclasses are encouraged to provide optimized resolution
for messages without arguments, not involving MessageFormat.
See resolveCodeWithoutArguments javadoc for details. |
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 can override this method to resolve a message without
arguments in an optimized fashion, that is, to resolve a message
without involving a MessageFormat.
The default implementation does use MessageFormat,
through delegating to the resolveCode method.
Subclasses are encouraged to replace this with optimized resolution.
Unfortunately, java.text.MessageFormat 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. |
public void setParentMessageSource(MessageSource parent) {
this.parentMessageSource = parent;
}
|
public void setUseCodeAsDefaultMessage(boolean useCodeAsDefaultMessage) {
this.useCodeAsDefaultMessage = useCodeAsDefaultMessage;
}
Set whether to use the message code as default message instead of
throwing a NoSuchMessageException. Useful for development and debugging.
Default is "false".
Note: In case of a MessageSourceResolvable with multiple codes
(like a FieldError) and a MessageSource that has a parent MessageSource,
do not activate "useCodeAsDefaultMessage" in the parent:
Else, you'll get the first code returned as message by the parent,
without attempts to check further codes.
To be able to work with "useCodeAsDefaultMessage" turned on in the parent,
AbstractMessageSource and AbstractApplicationContext contain special checks
to delegate to the internal getMessageInternal method if available.
In general, it is recommended to just use "useCodeAsDefaultMessage" during
development and not rely on it in production in the first place, though. |