Skip to content

Commit

Permalink
Avoid String concatenation for lookup in StaticMessageSource
Browse files Browse the repository at this point in the history
Closes gh-22451
  • Loading branch information
jhoeller committed Nov 13, 2019
1 parent 6fa9871 commit 3dc5e7b
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 19 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -36,33 +36,35 @@
*/
public class StaticMessageSource extends AbstractMessageSource {

/** Map from 'code + locale' keys to message Strings. */
private final Map<String, String> messages = new HashMap<>();

private final Map<String, MessageFormat> cachedMessageFormats = new HashMap<>();
private final Map<String, Map<Locale, MessageHolder>> messageMap = new HashMap<>();


@Override
@Nullable
protected String resolveCodeWithoutArguments(String code, Locale locale) {
return this.messages.get(code + '_' + locale.toString());
Map<Locale, MessageHolder> localeMap = this.messageMap.get(code);
if (localeMap == null) {
return null;
}
MessageHolder holder = localeMap.get(locale);
if (holder == null) {
return null;
}
return holder.getMessage();
}

@Override
@Nullable
protected MessageFormat resolveCode(String code, Locale locale) {
String key = code + '_' + locale.toString();
String msg = this.messages.get(key);
if (msg == null) {
Map<Locale, MessageHolder> localeMap = this.messageMap.get(code);
if (localeMap == null) {
return null;
}
synchronized (this.cachedMessageFormats) {
MessageFormat messageFormat = this.cachedMessageFormats.get(key);
if (messageFormat == null) {
messageFormat = createMessageFormat(msg, locale);
this.cachedMessageFormats.put(key, messageFormat);
}
return messageFormat;
MessageHolder holder = localeMap.get(locale);
if (holder == null) {
return null;
}
return holder.getMessageFormat();
}

/**
Expand All @@ -75,7 +77,7 @@ public void addMessage(String code, Locale locale, String msg) {
Assert.notNull(code, "Code must not be null");
Assert.notNull(locale, "Locale must not be null");
Assert.notNull(msg, "Message must not be null");
this.messages.put(code + '_' + locale.toString(), msg);
this.messageMap.computeIfAbsent(code, key -> new HashMap<>(4)).put(locale, new MessageHolder(msg, locale));
if (logger.isDebugEnabled()) {
logger.debug("Added message [" + msg + "] for code [" + code + "] and Locale [" + locale + "]");
}
Expand All @@ -95,7 +97,41 @@ public void addMessages(Map<String, String> messages, Locale locale) {

@Override
public String toString() {
return getClass().getName() + ": " + this.messages;
return getClass().getName() + ": " + this.messageMap;
}


private class MessageHolder {

private final String message;

private final Locale locale;

@Nullable
private volatile MessageFormat cachedFormat;

public MessageHolder(String message, Locale locale) {
this.message = message;
this.locale = locale;
}

public String getMessage() {
return this.message;
}

public MessageFormat getMessageFormat() {
MessageFormat messageFormat = this.cachedFormat;
if (messageFormat == null) {
messageFormat = createMessageFormat(this.message, this.locale);
this.cachedFormat = messageFormat;
}
return messageFormat;
}

@Override
public String toString() {
return this.message;
}
}

}
Expand Up @@ -59,7 +59,6 @@ public class StaticMessageSourceTests extends AbstractApplicationContextTests {
@Test
@Override
public void count() {
// These are only checked for current Ctx (not parent ctx)
assertCount(15);
}

Expand Down

0 comments on commit 3dc5e7b

Please sign in to comment.