From 0def7644c2eaefc73328f257d5f53bbf615de397 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Tue, 3 Jun 2014 15:53:46 +0100 Subject: [PATCH] Check for existence of ResourceBundle before creating MessageSource Irritatingly a ResourceBundleMessageSource never gives up trying to create a resource bundle for every message resolution, so to stop it logging all those warnings (and probably sucking performance-wise) we need to disable the MessageSource if a bundle is not provided. Fixes gh-1019 --- .../MessageSourceAutoConfiguration.java | 90 +++++++++++++++---- .../MessageSourceAutoConfigurationTests.java | 12 +-- 2 files changed, 80 insertions(+), 22 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/MessageSourceAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/MessageSourceAutoConfiguration.java index c597ea0240..60b97f0f8b 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/MessageSourceAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/MessageSourceAutoConfiguration.java @@ -16,16 +16,25 @@ package org.springframework.boot.autoconfigure; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration.ResourceBundleCondition; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.bind.RelaxedPropertyResolver; -import org.springframework.context.EnvironmentAware; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; -import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.util.StringUtils; import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; @@ -39,28 +48,77 @@ import static org.springframework.util.StringUtils.trimAllWhitespace; @Configuration @ConditionalOnMissingBean(MessageSource.class) @Order(Ordered.HIGHEST_PRECEDENCE) -public class MessageSourceAutoConfiguration implements EnvironmentAware { +@Conditional(ResourceBundleCondition.class) +@EnableConfigurationProperties +@ConfigurationProperties(prefix = "spring.messages") +public class MessageSourceAutoConfiguration { - private RelaxedPropertyResolver environment; + private String basename = "messages"; - @Override - public void setEnvironment(Environment environment) { - this.environment = new RelaxedPropertyResolver(environment, "spring.messages."); - } + private String encoding = "utf-8"; + + private int cacheSeconds = -1; @Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); - String basename = this.environment.getProperty("basename", "messages"); - if (StringUtils.hasText(basename)) { + if (StringUtils.hasText(this.basename)) { messageSource - .setBasenames(commaDelimitedListToStringArray(trimAllWhitespace(basename))); + .setBasenames(commaDelimitedListToStringArray(trimAllWhitespace(this.basename))); } - String encoding = this.environment.getProperty("encoding", "utf-8"); - messageSource.setDefaultEncoding(encoding); - messageSource.setCacheSeconds(this.environment.getProperty("cacheSeconds", - Integer.class, -1)); + messageSource.setDefaultEncoding(this.encoding); + messageSource.setCacheSeconds(this.cacheSeconds); return messageSource; } + public String getBasename() { + return this.basename; + } + + public void setBasename(String basename) { + this.basename = basename; + } + + public String getEncoding() { + return this.encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public int getCacheSeconds() { + return this.cacheSeconds; + } + + public void setCacheSeconds(int cacheSeconds) { + this.cacheSeconds = cacheSeconds; + } + + protected static class ResourceBundleCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + String basename = context.getEnvironment().getProperty( + "spring.messages.basename", "messages"); + if (!StringUtils.hasText(basename)) { + return ConditionOutcome.noMatch("Empty spring.messages.basename"); + } + for (String name : commaDelimitedListToStringArray(trimAllWhitespace(basename))) { + try { + ResourceBundle.getBundle(name, Locale.getDefault(), + context.getClassLoader()); + } + catch (MissingResourceException e) { + return ConditionOutcome + .noMatch("Bundle found for spring.messages.basename: " + name); + } + } + return ConditionOutcome.match("Bundle found for spring.messages.basename: " + + basename); + } + + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/MessageSourceAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/MessageSourceAutoConfigurationTests.java index 1b96c68a06..d0378941d2 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/MessageSourceAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/MessageSourceAutoConfigurationTests.java @@ -46,10 +46,10 @@ public class MessageSourceAutoConfigurationTests { @Test public void testMessageSourceCreated() throws Exception { this.context = new AnnotationConfigApplicationContext(); - this.context.register(MessageSourceAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, "spring.messages.basename:test/messages"); + this.context.register(MessageSourceAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); assertEquals("bar", this.context.getMessage("foo", null, "Foo message", Locale.UK)); @@ -58,10 +58,10 @@ public class MessageSourceAutoConfigurationTests { @Test public void testMultipleMessageSourceCreated() throws Exception { this.context = new AnnotationConfigApplicationContext(); - this.context.register(MessageSourceAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, "spring.messages.basename:test/messages,test/messages2"); + this.context.register(MessageSourceAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); assertEquals("bar", this.context.getMessage("foo", null, "Foo message", Locale.UK)); @@ -72,10 +72,10 @@ public class MessageSourceAutoConfigurationTests { @Test public void testBadEncoding() throws Exception { this.context = new AnnotationConfigApplicationContext(); - this.context.register(MessageSourceAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, "spring.messages.encoding:rubbish"); + this.context.register(MessageSourceAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); // Bad encoding just means the messages are ignored assertEquals("blah", this.context.getMessage("foo", null, "blah", Locale.UK));