Skip to content

Commit

Permalink
Add ReloadableResourceBundleMessageSource support
Browse files Browse the repository at this point in the history
Add a `spring.messages.reloadable` configuration property which can be
used to auto-configure a `ReloadableResourceBundleMessageSource` rather
than a `ResourceBundleMessageSource`.

Closes gh-13377
  • Loading branch information
ruifigueira authored and philwebb committed Oct 5, 2018
1 parent 8b59503 commit 22abe35
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 1 deletion.
Expand Up @@ -33,6 +33,8 @@
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.AbstractResourceBasedMessageSource;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.Ordered;
import org.springframework.core.io.Resource;
Expand Down Expand Up @@ -65,7 +67,9 @@ public MessageSourceProperties messageSourceProperties() {

@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
AbstractResourceBasedMessageSource messageSource = (properties.isReloadable()
? new ReloadableResourceBundleMessageSource()
: new ResourceBundleMessageSource());
if (StringUtils.hasText(properties.getBasename())) {
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(properties.getBasename())));
Expand Down
Expand Up @@ -71,6 +71,12 @@ public class MessageSourceProperties {
*/
private boolean useCodeAsDefaultMessage = false;

/**
* Whether to use a "ReloadableResourceBundleMessageSource" rather than the default
* "ResourceBundleMessageSource". Recommended during development only.
*/
private boolean reloadable = false;

public String getBasename() {
return this.basename;
}
Expand Down Expand Up @@ -119,4 +125,12 @@ public void setUseCodeAsDefaultMessage(boolean useCodeAsDefaultMessage) {
this.useCodeAsDefaultMessage = useCodeAsDefaultMessage;
}

public boolean isReloadable() {
return this.reloadable;
}

public void setReloadable(boolean reloadable) {
this.reloadable = reloadable;
}

}
Expand Up @@ -21,6 +21,7 @@
import org.junit.Ignore;
import org.junit.Test;

import org.springframework.beans.BeansException;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
Expand All @@ -32,6 +33,9 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.DelegatingMessageSource;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.context.support.ResourceBundleMessageSource;

import static org.assertj.core.api.Assertions.assertThat;

Expand Down Expand Up @@ -220,6 +224,43 @@ public void existingMessageSourceInParentIsIgnored() {
.isEqualTo("bar")));
}

@Test
public void testDefaultReloadableValueMessageSource() {
this.contextRunner.withPropertyValues("spring.messages.basename:test/messages")
.run((context) -> assertThat(getDeclaredMessageSource(context))
.isInstanceOf(ResourceBundleMessageSource.class));
}

@Test
public void testNotReloadableMessageSource() {
this.contextRunner
.withPropertyValues("spring.messages.basename:test/messages",
"spring.messages.reloadable:false")
.run((context) -> assertThat(getDeclaredMessageSource(context))
.isInstanceOf(ResourceBundleMessageSource.class));
}

@Test
public void testReloadableMessageSource() {
this.contextRunner.withPropertyValues("spring.messages.basename:test/messages",
"spring.messages.reloadable:true").run((context) -> {
assertThat(getDeclaredMessageSource(context))
.isInstanceOf(ReloadableResourceBundleMessageSource.class);
assertThat(context.getMessage("foo", null, "Foo message", Locale.UK))
.isEqualTo("bar");
});
}

private MessageSource getDeclaredMessageSource(AssertableApplicationContext context)
throws BeansException {
MessageSource messageSource = context.getBean(MessageSource.class);
if (messageSource instanceof DelegatingMessageSource) {
messageSource = ((DelegatingMessageSource) messageSource)
.getParentMessageSource();
}
return messageSource;
}

@Configuration
@PropertySource("classpath:/switch-messages.properties")
protected static class Config {
Expand Down
Expand Up @@ -133,6 +133,7 @@ content into your application. Rather, pick only the properties that you need.
spring.messages.cache-duration= # Loaded resource bundle files cache duration. When not set, bundles are cached forever. If a duration suffix is not specified, seconds will be used.
spring.messages.encoding=UTF-8 # Message bundles encoding.
spring.messages.fallback-to-system-locale=true # Whether to fall back to the system Locale if no files for a specific Locale have been found.
spring.messages.reloadable=false # Whether to use a ReloadableResourceBundleMessageSource instead of the default ResourceBundleMessageSource. Recommended during development only.
spring.messages.use-code-as-default-message=false # Whether to use the message code as the default message instead of throwing a "NoSuchMessageException". Recommended during development only.
# OUTPUT
Expand Down

0 comments on commit 22abe35

Please sign in to comment.