I am enabling message i18n in my Spring web app. For this, I have below code in my servlet.xml
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
After adding above code, as soon as I hit my application in browser, I get below exception log:
SEVERE: Servlet.service() for servlet [default] in context with path [/ERP-Web] threw exception [Filter execution threw an exception] with root cause
java.lang.StackOverflowError
at org.springframework.context.support.ReloadableResourceBundleMessageSource.getMergedProperties(ReloadableResourceBundleMessageSource.java:235)
at org.springframework.context.support.ReloadableResourceBundleMessageSource.resolveCodeWithoutArguments(ReloadableResourceBundleMessageSource.java:176)
at org.springframework.context.support.AbstractMessageSource.getMessageInternal(AbstractMessageSource.java:209)
at org.springframework.context.support.AbstractMessageSource.getMessageFromParent(AbstractMessageSource.java:257)
where last 2 lines were repeated 100s of times and gives me StackoverflowException.
Exactly same exception is coming when I am using ResourceBundleMessageSource class.
My spring version is 4.3.6.RELEASE.
Below is content of my properties file
action.add.success = New {0} added successfully.
action.add.failure = Some error occurred in adding new {0}. Please try again later or contact administrator.
Sample project is on GitHub
I have tested your sample code in github and when running it has shown the error described, then modify the following:
Config:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
Class:
#RequestMapping(method=RequestMethod.GET)
#ResponseBody
public String getMessage() {
String msg = messageSource.getMessage("hello.world", null, LocaleContextHolder.getLocale());
return msg;
}
hello.word is the property with text in your file with name message_en.properties.
With this modifications the code run.
Edit for unknown message codes:
I tried with unknown message codes and the error was repeated, so I look at the registry and found that there could be more than one beans with the same name (potential circular references), but I have not detected why this happens, but if you It needs to work you have to rename the beans like this.
<bean id="myMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
and then use:
#Autowired
private MessageSource myMessageSource;
but i think this not resolve the principal problem with the circular potential error.
Very strange situation ;-)
The fundamental problem is that the messageSource gets auto-wired to itself (in the parentMessageSource property) because you use default-autowire="byType" this causes the stackoverflow exceptions for unknown message codes that messes up everything. Must say that logback adds mess to the mess as sometimes seems that the exception happens in its code, Log4J handles it better.
Autowiring is not good for big projects, and this your situation is a classical case of why, however if you must use it change the messageSource bean adding the following:
<property name="parentMessageSource"><null/></property>
In this way you wire yourself the parent and no autowiring happens.
This restores the normal situation in which not found messages are reported with a NoSuchMessageException
Then:
In controller you must request hello.world message, not message
You are missing a default resource, that is a no-locale-suffix file that represents the default locale or your application. In your case would be messages/message.properties To be simple the default locale of your application is that one for which you have all messages. Start with that and then add new languages (that might be incomplete).
Update
As far as I run your demo project:
Remove default-autowire="byType", which will set your message source's parent to itself, which causes stackoverflow;
Avoid LocaleContextHolder.getLocale(), which relay on system default locale;
Use right basename, which is different for ReloadableResourceBundleMessageSource and ResourceBundleMessageSource which solves following warning;
ResourceBundle [messages/message] not found for MessageSource: Can't find bundle for base name messages/message, locale en_US
Runnable example
StackTrace
As far as I could see from your stack trace, you may have three problems:
You don't supply arguments, but your property needs it;
The message source you have has cyclic dependency with its parent, which causes the StackOverflow (because AbstractMessageSource has a model like classloader, i.e. delegation to parent if it can't resolve);
I am not sure whether your properties is really found by message source, if it found, even with cyclic dependency, it will not StackOverflow;
Suggestions
When it comes to why there exists cyclic dependency, I can't tell whether it is a bug of spring or mis-configuration according to current info;
If you are not convenient to provide a example project, you may try 4.1.6 Relase, which I tried, works fine;
You may set log level to DEBUG or set breakpoint, to see whether you property file is really loaded;
The way you should use the ResourceBundleMessageSource is setting the path to the messages files on the basename property.
For example, if you have two messages files:
messages_en.properties
messages_es.properties
located at resources folder. Your bean configuration should be something like:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
Where messages is the prefix of the name of both files.
Maybe the Exception is thrown because Spring id trying to load the classpath automatically, and you have it included too, so it tries to load it again and again...
You can find a working example on Mkyong's.
This is what worked for me in my applicationContext.xml file:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:i18n/message" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<ref bean="localeChangeInterceptor" />
</property>
</bean>
Note that i put the properties files in the follwoing path :
src/main/resources/i18n/message_en.properties
Below is the project-structure showing where I keep my messages files:
Web
Java Resources
src/main/resources
messages_en.properties
messages_fr.properties
Bean configuration file where I define message source looks like as shown below:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>messages_fr</value>
</list>
</property>
</bean>
I am new to this concept of internationalization. So don't know much except that if you put your .properies file inside the tag it will be picked and changes will be reflected. But I am facing problem in dealing with multiple .properties files.
Say If I have more than one .properties file then how should I implement locale changes? How would the program know which file to take?
You should use :
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>messages</value>
</list>
</property>
</bean>enter code here
Spring will use the local specified when you are calling the message bundle, so you don't have to specify it the declaration of your bundle.
Note : I think that you have to name your file :
messages_fr_FR.properties or messages_en_EN.properties.
Edit :
You can specify a local using :
messageSource.getMessage("messageKey", args, Locale.FRANCE);
to use messages_fr_FR
or
messageSource.getMessage("messageKey", args,LocaleContextHolder.getLocale());
to use the local selected by the user.
I hope it may help you
i have the next properties files with Spring Framework
config.properties
with content
environment=devel //posible values: devel, testing, prod
and with the previous environment property, choose some of the following files to load dynamically
config-service1-devel.properties
config-service1-testing.properties
config-service1-prod.properties
config-serviceN-devel.properties
config-serviceN-testing.properties
config-serviceN-prod.properties
and then, with spring i want load the properties, i'm solve to load the first properties file but i dont understand how to use expression language to complete the values of the dependent properties.
<bean id="MainApplicationProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location"
value="file://#{systemProperties['jboss.server.home.dir']}/conf/services.properties" />
<property name="placeholderPrefix" value="$mainProperty{" />
<property name="placeholderSuffix" value="}" />
</bean>
<bean id="SecondApplicationProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
depends-on="MainApplicationProperties">
<property name="locations">
<list>
<value>file://#{systemProperties['jboss.server.home.dir']}/conf/serviceOne/service1-$mainProperty{environment}.properties</value>
<value>file://#{systemProperties['jboss.server.home.dir']}/conf/serviceTwo/service2-$mainProperty{environment}.properties</value>
<value>file://#{systemProperties['jboss.server.home.dir']}/conf/serviceN/serviceN-$mainProperty{environment}.properties</value>
</list>
</property>
</bean>
the error output is the next,
java.io.FileNotFoundException: /..../conf/serviceOne/service1-$mainProperty{environment}.properties (No such file or directory)
my opinion is, the value has not replaced
helpme, thanks
The problem is that when BeanFactoryPostProcessors are starting to be invoked, they are already instantiated. So even thou the first PropertyPlaceholderConfigurer modifies the bean definition of the second PropertyPlaceholderConfigurer, it has no effect as both beans have been already instantiated.
I have a spring MVC web application that has the following structure:
myapp
|-META-INF
|-WEB-INF
|-classes
| |-conf
|-application.properties
|-lib
| |-externalApp.jar
| |-conf
| |-applicationContext.xml
|
|-applicationContext.xml
|-myapp-servlet.xml
In myapp/WEB-INF/applicationContext, i imported the applicationContext.xml file that is in the jar file as shown below:
<import resource="classpath:WEB-INF/conf/applicationContext.xml" />
The beans in the imported resource work fine and i can see them in my web application's controller/service classes.
The problem i have is that the
context file in the jar file (i.e. WEB-INF/lib/externalApp.jar/applicationContext.xml) has configuration for loading a properties file. The properties have to be set by the web application so the properties file is in the webapp. The configuration in the jar file's context file looks like this:
I want the above property to load the property file that is in the web application so i set its value to be as shown below:
<bean class="com.myapp.ExternalAppPropertyPlaceholderConfigurer">
<property name="location" value="classpath:conf/application.properties" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
With the above setting, the classes in the jar file that expect these properties to be availbe still cant get access to the properties.
The question i guess is how can i get the properties file that is in WEB-INF/classes/conf/application.properties to be accessible to the objects in the jar file that is located in WEB-INF/lib/externalApp.jar.
Looking at the stack traces i am getting, it looks as though the objects referred in the imported context file are loaded first before the properties are loaded which is not i want.
Thanks.
You can use the classpath*: prefix like this
<bean class="com.myapp.ExternalAppPropertyPlaceholderConfigurer">
<property name="location" value="classpath*:conf/application.properties" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
EDIT
Since your conf/application.properties is in your web app, you must define it in your web-app applicationContext (not in the jar as you do now). And define it before importing the applicationContext of your jar. i.e. put something like this in your web-app applicationContext:
<bean class="com.myapp.ExternalAppPropertyPlaceholderConfigurer">
<property name="location" value="classpath:conf/application.properties" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
<import resource="classpath*:/conf/applicationContext.xml" />
and remove the declaration of the properties from your jar applicationContext.
I am developing a Java desktop application and I am using Spring with it. Now I want to inject log4j to my classes using applicationContext.xml. My log4j properties file is placed in a source folder Resources/log4j.properties
During my search I found out that there are many way to it when its a web application but I found out no help regarding a desktop application.
I am using Apache commons interfaces in my source code and now I want to inject log4j dependency.
Kindly, help me out..
By default, Log4J will simply read its configuration from a "log4j.properties" file in the root of the class path. Since you placed your log4.properties file in the resources source folder, this should work.
If you do not want to store your log4j configuration in your class path then you can use something like this :
<bean id="log4jInitialization"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"
value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>myPropertiesFolder/log4j.xml</value>
</list>
</property>
</bean>