Is it possible to get Java fmt messages bundle from database? - java

I nedd to localize application and now files are loaded from text files. Is it possible to change source to database?
This is how localized messages are now loaded:
<!-- Application Message Bundle -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/messages/messages" />
<property name="cacheSeconds" value="0" />
</bean>

You can implement your own by extending AbstractMessageSource

Apparently this was asked in Spring some time ago but there were not enough people who wanted it I think.
https://jira.springsource.org/browse/SPR-364 is the JIRA and there is a JAVA file attached which is a good starting point (you need to set the SQL statement though)
Some relevant discussions are
http://forum.springsource.org/showthread.php?t=18194
http://forum.springsource.org/showthread.php?t=14610

Related

StackoverflowExcepton in Spring message i18n ReloadableResourceBundleMessageSource

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

How to set VM parameters from Spring with value from .properties? [duplicate]

One of our team has implemented loading properties this way (see pseudo code below) and advises this approach is right as the client application using this is free to keep the properties in any file. Contrary to the widely used propertyplaceholderconfigurer.
application-context.xml
<bean class="com.mypackage.Myclass">
<property name="xml" value="classpath:"{com.myapp.myproperty1}"> </property>
</bean>
config.properties
com.myapp.myproperty1=data.xml
edit: I should have added it is data.properties and not data.xml. We want to load a property file (this property file is given in the config.properties as a "property".
com.myapp.myproperty1=data.properties
java class
import org.springframework.core.io.Resource;
public class Myclass {
private Resource xmlField;
// setter & getter methods..
}
Is it right to use spring core.io.Resource?
Another reason is the client application wants to load a environment specific configuration. I suggested use the propertyconfigurer and use maven profiles to generate the environment specific build
Can you please advise which one suits which case? and if it differs in different scenarios, please help me point out them?
thanks
You can put the properties in any file and still use PropertyPlaceholderConfigurer. Here's an example that satisfies both your coworker's concerns and your desire for environment specific stuff:
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!-- default settings -->
<value>classpath:MyCompany.properties</value>
<!-- environment-specific settings -->
<value>classpath:MyCompany.${mycompany.env:dev}.properties</value>
<!-- keep your coworker happy -->
<value>classpath:${mycoworker}</value>
<!-- allows emergency reconfiguration via the local file system -->
<value>file:///${user.home}/MyCompany.properties</value>
</list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreResourceNotFound" value="true" />
<!-- should be validated separately, in case users of the library load additional properties -->
<property name="ignoreUnresolvablePlaceholders" value="false"/>
</bean>
If you pass in no -D arguments, then you'll pick up the following properties files, where properties in the later files overwrite previously determined values.
MyCompany.properties off the classpath
MyCompany.dev.properties off the classpath
$HOME/MyCompany.properties if it exists
To swap in a production config for #2, just pass -Dmycompany.env=prod to java. Similarly your coworker can pass -Dmycoworker=/some/path/config.properties if he/she wants.
I'm not sure why a PropertyPlaceholderConfigurator wouldn't have been the correct choice.
I've almost always handled environment-specific configs via a customized PPC that can either (a) get a -D parameter on startup, and/or (b) use the machine name, to decide which property file to load.
For me, this is more convenient than bundling the information in via Maven, since I can more easily test arbitrary configurations from whatever machine I'm on (using a -D property).
+1 for Dave's suggestion. You should be using PropertyPlaceholderConfigurer for loading\reading properties. Here is the example i just pulled out from my previous project if you wonder how to use this. This example is for loading multiple properties files but the concept is same. Good luck.
<bean id="projectProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:config.properties</value>
</list>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="projectProperties" />
</bean>
<bean id="uniqueAssetIdRetriever" class="com.mypackage.Myclass">
<property name="xml" value="${com.myapp.myproperty1}" />
</bean>

Spring Message Not Displaying

I am trying to do internationalization in Spring-MVC for the first time and I'm having what I assume to be a configuration issue. I have a NLS file that I named NLS_en.properties which I placed in my application's WEB-INF\classes directory. The file contains the following NLS string:
MSG_HELLO = Hello to the Internationalized World
In my application's servlet.xml file I've defined the following beans:
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en" />
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="WEB-INF/classes/NLS"/>
</bean>
In my JSP file I have the following tag:
<p><spring:message code="MSG_HELLO" text="You should not be seeing this text" />
When the JSP displays, of course, the message I see is the one I should not be seeing, so how do I have to configure my application so that I do see my HELLO message?
ResourceBundleMessageSource basename (as opposed to ReloadableResourceBundleMessageSource) refers by default to the classpath, so you should have it like :
<property name="basename" value="NLS" />
Now, depending on how you build, even if configuring correctly the message source, it may have been erased at the time you run the application.
Do not place resources directly into classes (or any target directory in general). If you use maven place it directly into resources. If you dont use any build framework put it in the root of the source directory.

loading properties file in spring

One of our team has implemented loading properties this way (see pseudo code below) and advises this approach is right as the client application using this is free to keep the properties in any file. Contrary to the widely used propertyplaceholderconfigurer.
application-context.xml
<bean class="com.mypackage.Myclass">
<property name="xml" value="classpath:"{com.myapp.myproperty1}"> </property>
</bean>
config.properties
com.myapp.myproperty1=data.xml
edit: I should have added it is data.properties and not data.xml. We want to load a property file (this property file is given in the config.properties as a "property".
com.myapp.myproperty1=data.properties
java class
import org.springframework.core.io.Resource;
public class Myclass {
private Resource xmlField;
// setter & getter methods..
}
Is it right to use spring core.io.Resource?
Another reason is the client application wants to load a environment specific configuration. I suggested use the propertyconfigurer and use maven profiles to generate the environment specific build
Can you please advise which one suits which case? and if it differs in different scenarios, please help me point out them?
thanks
You can put the properties in any file and still use PropertyPlaceholderConfigurer. Here's an example that satisfies both your coworker's concerns and your desire for environment specific stuff:
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!-- default settings -->
<value>classpath:MyCompany.properties</value>
<!-- environment-specific settings -->
<value>classpath:MyCompany.${mycompany.env:dev}.properties</value>
<!-- keep your coworker happy -->
<value>classpath:${mycoworker}</value>
<!-- allows emergency reconfiguration via the local file system -->
<value>file:///${user.home}/MyCompany.properties</value>
</list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreResourceNotFound" value="true" />
<!-- should be validated separately, in case users of the library load additional properties -->
<property name="ignoreUnresolvablePlaceholders" value="false"/>
</bean>
If you pass in no -D arguments, then you'll pick up the following properties files, where properties in the later files overwrite previously determined values.
MyCompany.properties off the classpath
MyCompany.dev.properties off the classpath
$HOME/MyCompany.properties if it exists
To swap in a production config for #2, just pass -Dmycompany.env=prod to java. Similarly your coworker can pass -Dmycoworker=/some/path/config.properties if he/she wants.
I'm not sure why a PropertyPlaceholderConfigurator wouldn't have been the correct choice.
I've almost always handled environment-specific configs via a customized PPC that can either (a) get a -D parameter on startup, and/or (b) use the machine name, to decide which property file to load.
For me, this is more convenient than bundling the information in via Maven, since I can more easily test arbitrary configurations from whatever machine I'm on (using a -D property).
+1 for Dave's suggestion. You should be using PropertyPlaceholderConfigurer for loading\reading properties. Here is the example i just pulled out from my previous project if you wonder how to use this. This example is for loading multiple properties files but the concept is same. Good luck.
<bean id="projectProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:config.properties</value>
</list>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="projectProperties" />
</bean>
<bean id="uniqueAssetIdRetriever" class="com.mypackage.Myclass">
<property name="xml" value="${com.myapp.myproperty1}" />
</bean>

Building custom Spring config tags for a framework

I have a framework which currently requires pretty verbose setup in Spring:
<bean id="dpHibernateRemotingAdapter"
class="org.springframework.flex.core.ManageableComponentFactoryBean">
<constructor-arg value="org.dphibernate.adapters.RemotingAdapter" />
<property name="properties">
<value>
{"dpHibernate" :
{
"serializerFactory" : "org.dphibernate.serialization.SpringContextSerializerFactory"
}
}
</value>
</property>
</bean>
<bean id="dataAccessService" class="org.dphibernate.services.SpringLazyLoadService"
autowire="constructor">
<flex:remoting-destination />
</bean>
<bean id="dpHibernateSerializer" class="org.dphibernate.serialization.HibernateSerializer"
scope="prototype">
<property name="pageSize" value="10" />
</bean>
<bean id="dpHibernateDeserializer" class="org.dphibernate.serialization.HibernateDeserializer"
scope="prototype" />
I'd like to look at providing a more elegant configuration tag, similar to user-friendly tags used elsewhere in spring:
<context:annotation-config />
<mvc:annotation-driven />
<tx:annotation-driven />
<flex:message-broker/>
etc.,
However, I don't really know where to start.
How does this approach work? What are these tags called? What's their base class?
If someone could point me to the class names in the source (ideally, the <flex:message-broker />, as that's the closest problem set to my project), then I can go from there. I just don't really know where to start!
Custom XML namespaces are certainly possible (see Appendix D), but in my experience a royal pain to get working properly.
I strongly recommend that instead you use #Bean-style configuration. This lets you use Java to compose your bean graphs, instead of XML. Not only can it be much more concise in certain situations, it's properly type-safe, and more easily re-used.
Either way, you'll end up writing some Java that wires objects together. It's a question of how you want to expose that.
See Appendix D. Extensible XML authoring.

Categories

Resources