Does Spring MessageSource Support Multiple Class Path?
The issue here is not with multiple classpaths or classloaders, but with how many resources the code will try and load for a given path.
The classpath*
syntax is a Spring mechanism, one which allows code to load multiple resources for a given path. Very handy. However, ResourceBundleMessageSource
uses the standard java.util.ResourceBundle
to load the resources, and this is a much simpler, dumber mechanism, which will load the first resource for a given path, and ignore everything else.
I don't really have an easy fix for you. I think you're going to have to ditch ResourceBundleMessageSource
and write a custom implementation of MessageSource
(most likely by subclassing AbstractMessageSource
) which uses PathMatchingResourcePatternResolver
to locate the various resources and expose them via the MessageSource
interface. ResourceBundle
isn't going to be much help.
With the solution of @seralex-vi basenames /WEB-INF/messages did not function.
I overwrited the method refreshProperties on the class ReloadableResourceBundleMessageSource wich perform both type of basenames (classpath*: and /WEB-INF/)
public class SmReloadableResourceBundleMessageSource extends ReloadableResourceBundleMessageSource {
private static final String PROPERTIES_SUFFIX = ".properties";
private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
@Override
protected PropertiesHolder refreshProperties(String filename, PropertiesHolder propHolder) {
if (filename.startsWith(PathMatchingResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) {
return refreshClassPathProperties(filename, propHolder);
} else {
return super.refreshProperties(filename, propHolder);
}
}
private PropertiesHolder refreshClassPathProperties(String filename, PropertiesHolder propHolder) {
Properties properties = new Properties();
long lastModified = -1;
try {
Resource[] resources = resolver.getResources(filename + PROPERTIES_SUFFIX);
for (Resource resource : resources) {
String sourcePath = resource.getURI().toString().replace(PROPERTIES_SUFFIX, "");
PropertiesHolder holder = super.refreshProperties(sourcePath, propHolder);
properties.putAll(holder.getProperties());
if (lastModified < resource.lastModified())
lastModified = resource.lastModified();
}
} catch (IOException ignored) {
}
return new PropertiesHolder(properties, lastModified);
}
On the spring-context.xml you must have the classpath*: prefix
<bean id="messageSource" class="SmReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>/WEB-INF/i18n/enums</value>
<value>/WEB-INF/i18n/messages</value>
<value>classpath*:/META-INF/messages-common</value>
<value>classpath*:/META-INF/enums</value>
</list>
</property>
</bean>