(Reloadable)ResourceBundleMessageSource allows for custom PropertyResourceBundle/Properties subclasses

Issue: SPR-12666
This commit is contained in:
Juergen Hoeller 2015-03-06 17:45:37 +01:00
parent 450072e38a
commit 71cdf856e1
2 changed files with 39 additions and 19 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -345,7 +345,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractMessageSource
if (mergedHolder != null) { if (mergedHolder != null) {
return mergedHolder; return mergedHolder;
} }
Properties mergedProps = new Properties(); Properties mergedProps = newProperties();
mergedHolder = new PropertiesHolder(mergedProps, -1); mergedHolder = new PropertiesHolder(mergedProps, -1);
for (int i = this.basenames.length - 1; i >= 0; i--) { for (int i = this.basenames.length - 1; i >= 0; i--) {
List<String> filenames = calculateAllFilenames(this.basenames[i], locale); List<String> filenames = calculateAllFilenames(this.basenames[i], locale);
@ -565,7 +565,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractMessageSource
*/ */
protected Properties loadProperties(Resource resource, String filename) throws IOException { protected Properties loadProperties(Resource resource, String filename) throws IOException {
InputStream is = resource.getInputStream(); InputStream is = resource.getInputStream();
Properties props = new Properties(); Properties props = newProperties();
try { try {
if (resource.getFilename().endsWith(XML_SUFFIX)) { if (resource.getFilename().endsWith(XML_SUFFIX)) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
@ -601,6 +601,19 @@ public class ReloadableResourceBundleMessageSource extends AbstractMessageSource
} }
} }
/**
* Template method for creating a plain new {@link Properties} instance.
* The default implementation simply calls {@link Properties#Properties()}.
* <p>Allows for returning a custom {@link Properties} extension in subclasses.
* Overriding methods should just instantiate a custom {@link Properties} subclass,
* with no further initialization or population to be performed at that point.
* @return a plain Properties instance
* @since 4.2
*/
protected Properties newProperties() {
return new Properties();
}
/** /**
* Clear the resource bundle cache. * Clear the resource bundle cache.

View File

@ -19,6 +19,7 @@ package org.springframework.context.support;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.security.AccessController; import java.security.AccessController;
@ -67,7 +68,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
private String[] basenames = new String[0]; private String[] basenames = new String[0];
private String defaultEncoding; private String defaultEncoding = "ISO-8859-1";
private boolean fallbackToSystemLocale = true; private boolean fallbackToSystemLocale = true;
@ -150,9 +151,9 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
/** /**
* Set the default charset to use for parsing resource bundle files. * Set the default charset to use for parsing resource bundle files.
* <p>Default is none, using the {@code java.util.ResourceBundle} * <p>Default is the {@code java.util.ResourceBundle} default encoding:
* default encoding: ISO-8859-1. * ISO-8859-1.
* and more flexibility in setting of an encoding per file. * @since 3.1.3
*/ */
public void setDefaultEncoding(String defaultEncoding) { public void setDefaultEncoding(String defaultEncoding) {
this.defaultEncoding = defaultEncoding; this.defaultEncoding = defaultEncoding;
@ -167,6 +168,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* {@code java.util.ResourceBundle}. However, this is often not desirable * {@code java.util.ResourceBundle}. However, this is often not desirable
* in an application server environment, where the system Locale is not relevant * in an application server environment, where the system Locale is not relevant
* to the application at all: Set this flag to "false" in such a scenario. * to the application at all: Set this flag to "false" in such a scenario.
* @since 3.1.3
*/ */
public void setFallbackToSystemLocale(boolean fallbackToSystemLocale) { public void setFallbackToSystemLocale(boolean fallbackToSystemLocale) {
this.fallbackToSystemLocale = fallbackToSystemLocale; this.fallbackToSystemLocale = fallbackToSystemLocale;
@ -188,6 +190,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* Consider {@link ReloadableResourceBundleMessageSource} in combination * Consider {@link ReloadableResourceBundleMessageSource} in combination
* with resource bundle files in a non-classpath location. * with resource bundle files in a non-classpath location.
* </ul> * </ul>
* @since 3.1.3
*/ */
public void setCacheSeconds(int cacheSeconds) { public void setCacheSeconds(int cacheSeconds) {
this.cacheMillis = (cacheSeconds * 1000); this.cacheMillis = (cacheSeconds * 1000);
@ -304,18 +307,24 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* @param locale the Locale to look for * @param locale the Locale to look for
* @return the corresponding ResourceBundle * @return the corresponding ResourceBundle
* @throws MissingResourceException if no matching bundle could be found * @throws MissingResourceException if no matching bundle could be found
* @see java.util.ResourceBundle#getBundle(String, java.util.Locale, ClassLoader) * @see java.util.ResourceBundle#getBundle(String, Locale, ClassLoader)
* @see #getBundleClassLoader() * @see #getBundleClassLoader()
*/ */
protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException { protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException {
if ((this.defaultEncoding != null && !"ISO-8859-1".equals(this.defaultEncoding)) || return ResourceBundle.getBundle(basename, locale, getBundleClassLoader(), new MessageSourceControl());
!this.fallbackToSystemLocale || this.cacheMillis >= 0) { }
return ResourceBundle.getBundle(basename, locale, getBundleClassLoader(), new MessageSourceControl());
} /**
else { * Load a property-based resource bundle from the given reader.
// Good old standard call... * <p>The default implementation returns a {@link PropertyResourceBundle}.
return ResourceBundle.getBundle(basename, locale, getBundleClassLoader()); * @param reader the reader for the target resource
} * @return the fully loaded bundle
* @throws IOException in case of I/O failure
* @since 4.2
* @see PropertyResourceBundle#PropertyResourceBundle(Reader)
*/
protected ResourceBundle loadBundle(Reader reader) throws IOException {
return new PropertyResourceBundle(reader);
} }
/** /**
@ -430,9 +439,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
} }
if (stream != null) { if (stream != null) {
try { try {
return (defaultEncoding != null ? return loadBundle(new InputStreamReader(stream, defaultEncoding));
new PropertyResourceBundle(new InputStreamReader(stream, defaultEncoding)) :
new PropertyResourceBundle(stream));
} }
finally { finally {
stream.close(); stream.close();