spring i18n: problem with multiple property files - spring

My messages.properties is really a big file.
So, I tried moving some of the properties in messages.properties to a new file, say newmessages.properties and updated spring bean configuration xml with both the files as follows:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:i18n/messages"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<bean id="anotherMessageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:i18n/newmessages"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
But, I am not able access any properties defined in the new property file.
Is it really possible to specify multiple property files(for a single locale)?

The basenames (s at the end) property accept an array of basenames:
Set an array of basenames, each following the above-mentioned special convention. The associated resource bundles will be checked sequentially when resolving a message code.
#see java doc: ReloadableResourceBundleMessageSource.setBasenames
So you should have only one messages source, with a list files (try to seperatate them by comma).
<bean id="anotherMessageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames" value="classpath:i18n/newmessages,classpath:i18n/messages"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>

Another clean way to doing same:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messages1</value>
<value>classpath:messages2</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
</bean>

Alternative solution to those already mentioned would be using the property parentMessageSource that delegates the message lookup to the parent if it does not find it in the current instance.
In your case it is probably better to stay with the basenames array. Having the hierarchic message source could make more sense if the message sources were using different implementations. E.g. the second one reading messages from db.
Note that in this case, when Spring finds two instances of MessageSource, so the primary one will be the one with the id messageSource.
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="parentMessageSource"><ref bean="anotherMessageSource"/></property>
<property name="basename" value="classpath:i18n/messages"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<bean id="anotherMessageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:i18n/newmessages"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>

For those(like me), looking for java config solution :
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("i18n/messages", "i18n/newmessages");
return messageSource;
}
jdoc : http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/support/AbstractResourceBasedMessageSource.html#setBasenames-java.lang.String...-

I've successfully loaded multiple messages properties into a spring boot application with following bean configuration.
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource
= new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:/messages/exception/messages",
"classpath:/messages/response/messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}

Related

How to get key value from properties file at runtime using spring

I want to get the changed key value from properties file at runtime.
test.properties file:
name = Hi
I have made Thread sleep with 5 sec and changed the key value as "Hello" but it is not getting changed.
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:test.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:test</value>
</list>
</property>
<property name="cacheSeconds" value="1" />
</bean>
<bean id="tempBean" name="tempBean1" class="org.sri.spring.temp.Temp"
lazy-init="false" scope="prototype">
<constructor-arg type="String" value="${name}" />
</bean>
The ${name} placeholder inside the XML configuration is resolved using the PropertySourcesPlaceholderConfigurer which, as you may notice, has nothing in common with your reloadable messageSource.
It wouldn't work either way because Spring instantiates the tempBean only once: on application startup, by passing the value of ${name} to the constructor. The bean itself is not aware of where the value came from (and in particular, it doesn't care if the properties file gets edited).
If you really think it's a good idea to do it†, you can inject the entire messageSource into your tempBean, and get the current value in each call, e.g.:
public class Temp {
#Autowired // or wired in XML, constructor, etc.
private MessageSource messages;
public String sayHello() {
return messages.getMessage("name", null, Locale.getDefault());
}
}
† injecting a configuration-related object makes testing more difficult and is arguably bad design (mixing concerns). Have a look at the Spring Cloud Config project as it's likely that this is how the future is going to look like.
I do not think that Spring will update already existing beans when the properties change.
Try to create a new bean (prototype scope)

Spring static factory with factory-method and parameter

I have a problem transfering code to Spring applicationContext.xml
The source is:
File inFile = new File ("path/to/file/", "fileName.docx")
WordprocessingMLPackage wordMLPackage = Docx4J.load(inFile);
My not working solution is:
<bean id="inFile" class="java.io.File">
<constructor-arg value="path/to/file/" />
<constructor-arg value="fileName.docx" />
</bean>
<bean id="docx4j" class="org.docx4j.Docx4J" factory-method="load">
<constructor-arg ref="inFile" />
</bean>
<bean id="wordprocessingMLPackage" class="org.docx4j.openpackaging.packages.WordprocessingMLPackage" factory-bean="docx4j" />
What I'm getting out of the bean "wordprocessingMLPackage" is indeed an instance of the Class WordprocessingMLPackage, but it seems empty although the File I'm trying to load isn't (and yes, the path is doublechecked).
When trying
MainDocumentPart mdp = wordprocessingMLPackage.getMainDocumentPart();
List<Object> content = mdp.getContent();
I'm getting a NullPointerException because mdp is null!
Has anyone an idea... or even a solution?
============================================================
I found a solution especially for my problem.
Here is the source of Docx4j.load():
public static WordprocessingMLPackage load(File inFile) throws Docx4JException {
return WordprocessingMLPackage.load(inFile);
}
That means I can create an instance of WordprocessingMLPackage by its static self!
The code which is working:
<bean id="wordprocessingMLPackage" class="org.docx4j.openpackaging.packages.WordprocessingMLPackage" factory-method="load">
<constructor-arg ref="baseDocument" />
</bean>
So I found a lucky "workaround" for the original problem.
Since this question isn't urgent any more, I'm still interested in the correct solution, especially in a solution which allows injecting the WordprocessingMLPackage in other beans.
Thank you!
Here you need to make use of MethodInvokingFactoryBean as detailed below.
<bean id="beanId"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.docx4j.Docx4J" />
<property name="targetMethod" value="load"/>
<property name="arguments">
<list>
<ref bean="inFile" />
</list>
</property>
</bean>
In your code get hold of applicationContext instance and invoke the below LOC
WordprocessingMLPackage ml = (WordprocessingMLPackage) applicationContext.getBean("beanId");
Let know in comments if you face any issues.
As Bond - Java Bond stated this works:
<bean id="inFile" class="java.io.File">
<constructor-arg value="path/to/file/" />
<constructor-arg value="fileName.docx" />
</bean>
<bean id="beanId" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.docx4j.Docx4J" />
<property name="targetMethod" value="load"/>
<property name="arguments">
<list>
<ref bean="inFile" />
</list>
</property>
</bean>
You can now use the bean as
WordprocessingMLPackage ml = (WordprocessingMLPackage) applicationContext.getBean("beanId");
or you can inject the bean directly as
<bean id="service" class="app.service.Service">
<property name="wordprocessingMLPackage" ref="beanId" />
</bean>
Thank you!!!

We want to get all the records in Database using HQL in terms of Spring and Hibernate

Here i tried 2 write cod 2 get list from Mysql Database using spring nd Hibernate.
But problem is here that how initialize **org.hibernate.Session se through "applicationContext.xml" file by bean class....
public void getList(**Session se**){
String liststudent="from StudentList stud";
Query q=se.createQuery(liststudent);
List<Object> list=q.list();
for(Object obj:list){
Object studarr[]=(Object[])obj;
System.out.println("Data at Zero Index"+studarr[0]);
}
}
As here property name **template** has been initialized by the ref template.
Is there any way to initialize Session se.
<bean name="mydao" class="dao.MyDao">
<property name="template" ref="template"></property>
</bean>
using your context.xml file
define sessionFactory
<bean id="sessionFactory" class="LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--define other properties...mapping files
</bean>
define hibernateTemplate
<bean id="template" class="*HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
then
<bean name="mydao" class="dao.MyDao">
<property name="template" ref="template"></property>
</bean>
NOTE: the class package has been ommitted

How can I get the number of line and the filename in itemProcessor - spring batch

I am using spring batch to parse my files. In ItemProcessor I validate if the incoming fields are correct. If they are not I want to throw a ValidationException and log to a file the corresponding row which has the incorrect fields. So, how can I find the number of line and the filename in ItemProcessor?
Without seeing you ItemReader config I can't really be sure but if you are using something like FlatFileItemReader to parse a csv, if in strict mode it will validate the number of columns.
Assuming you reader looks like this, that is:
<bean id="iItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="linesToSkip" value="1"/>
<property name="comments" value="#" />
<property name="encoding" value="UTF-8"/>
<property name="lineMapper" >
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value=","/>
<property name="names">
<list >
<value>First_Field</value>
<value>Second_Field</value>
</list>
</property>
<property name="strict" value="true"/>
</bean>
</property>
<property name="fieldSetMapper">
<bean class="uk.co.package.FieldSetMapper">
<property name="dateFormat" value="yyyy-MM-dd HH:mm:ss"/>
</bean>
</property>
</bean>
</property>
</bean>
It will throw a FlatFileParseException for any lines that can't be processed. This includes the line number and can be handled in a listener.
As for the line number, you might build your own LineMapper and then store the line-number in your business object. An example in which I store the line unprocessed (as-is) together with the line number:
DefaultLineMapper<OneRow> lineMapper = new DefaultLineMapper<OneRow>() {
#Override
public OneRow mapLine(String line, int lineNumber) throws Exception {
return new OneRow(lineNumber, line);
}
};
Of course you can already map your Object, I had the need to have the whole line unprocessed as input to my Processors.
As a reference with the same idea: https://stackoverflow.com/a/23770421/5658642

Spring - Retrieve value from properties file

I have the following configuration in my applicationContext.xml:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:app.properties</value>
</list>
</property>
</bean>
Now, in my java class, how can I read the values from the file app.properties?
With Spring 3.0 you can use the #Value annotation.
#Component
class MyComponent {
#Value("${valueKey}")
private String valueFromPropertyFile;
}
Actually PropertyPlaceholderConfigurer is useful to inject values to spring context using properties.
Example XML context definition:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>${driver}</value></property>
<property name="url"><value>jdbc:${dbname}</value></property>
</bean>`
Example properties file:
driver=com.mysql.jdbc.Driver
dbname=mysql:mydb
Or you can create bean like
<bean name="myBean" value="${some.property.key}" />
and then inject this bean into your class

Resources