How does one make Spring read from a file to string property? - spring

I have a bean that has a string property that I would like to set, but I would like it set from a file without changing the bean code. The bean is something like this.
public class SomeBean {
public void setSomeProperty(String string) { ... }
}
I was looking for something like this in the beans.xml file
<beans>
<bean class="SomeBean">
<property name="someProperty">
<util:string src="classpath:foo.txt" />
</property>
</bean>
</beans>

Try using the PropertyPlaceholderConfigurer to load a value from a properties file:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:foo.properties</value>
</list>
</property>
</bean>
<bean class="SomeBean">
<property name="someProperty" value="${myBean.someProperty}" />
Then, in the foo.properties file, you set the property to whatever value you want:
myBean.someProperty = value
Hope this helps

I found a way using the Guava classes though it looks really bad.
(The value attribute is all in one line)
<property name="someProperty"
value="#{ T(com.google.common.io.Resources).toString(
T(com.google.common.io.Resources).getResource('foo.txt'),
T(java.nio.charset.Charset).forName('UTF-8')) }"/>
Hopefully someone can find a better answer.

Related

How to provide reference bean to XmlViewResolver

i am generating Excel Sheet using Spring MVC , for this reason i have the following in my appcontext.xml file
appcontext.xml
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="order" value="1"/>
<property name="location" value="/WEB-INF/views.xml"/>
</bean>
views.xml
<bean id="excelView" class="com.xxxx.xx.util.MyListExcelView" />
​
Instead of having the bean reference excelView in a separate views.xml file .can we mention the below in the same appcontext.xml
<bean id="excelView" class="com.xxxx.xx.util.MyListExcelView" />
Sure, you can.
Just add BeanNameViewResolver to your ViewResolver chain.
Of course, you should remove excelView from views.xml in this case.
Here is an example:
appcontext.xml:
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="0"/>
</bean>
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="order" value="1"/>
<property name="location" value="/WEB-INF/views.xml"/>
</bean>
<bean id="excelView" class="com.xxxx.xx.util.MyListExcelView" />
YourController.java
#Controller
public class YourController {
// ...
#RequestMapping(value = "/test")
public String test() {
// populate your model here
return "excelView";
}
// ...
}

Spring Batch: Reading a File : if field is empty setting the default value

I am very new to spring batch. I have requirement in which i have to read a file having a header(Field Names) record and data records
i have to validate 1st record (check the field names matching against set of predefined names)- note that this record need to be skipped- i mean should not be part of items in processor)
read and store rest of the field values to a POJO
if the field 'date' is empty , i need to set the default value as 'xxxx-yy-zz'
i am unable to 1st and 3rd requirement with batch
here is the sample reader XML. please help
<bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="classpath:input/import" />
<property name="encoding" value="UTF-8" />
<property name="linesToSkip" value="1" />
<property name="lineMapper" ref="line.mapper"/>
</bean>
<bean id="line.mapper" class="org.springframework.batch.item.file.mapping .DefaultLineMapper">
<property name="lineTokenizer" ref="line.tokenizer"/>
<property name="fieldSetMapper" ref="fieldSet.enity.mapper"/>
</bean>
<bean id="line.tokenizer" class="org.springframework.batch.item.file.transfo rm.DelimitedLineTokenizer">
<property name="delimiter">
<util:constant static-field="org.springframework.batch.item.file.transfo rm.DelimitedLineTokenizer.DELIMITER_TAB"/>
</property>
<property name="names" value="id,date,age " />
<property name="strict" value="false"/>
</bean>
<bean id="fieldSet.enity.mapper" class="org.springframework.batch.item.file.mapping .BeanWrapperFieldSetMapper">
<property name="targetType" value="a.b.myPOJO"/>
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="org.springframework.beans.propertyeditors.C ustomDateEditor">
<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-mm-dd" />
</bean>
</constructor-arg>
<constructor-arg value="true" />
</bean>
</entry>
</map>
</property>
Create your own custom FieldSetMapper like below
CustomeFieldSetMapper implements FieldSetMapper<a.b.myPOJO> {
#Override
public a.b.myPOJO mapFieldSet(FieldSet fs) {
a.b.myPOJO myPOJO = new a.b.myPOJO();
if(fs.readString("date").isEmpty()){
myPOJO.setDate("xxxx-yy-zz");
}
return a.b.myPOJO;
}
}
You think you should do date set in ItemProcessor.
Also, if <property name="linesToSkip" value="1" /> not fill your requirements - extend FlatFileItemReader and validate first line manually in it.

Spring: Bean init method is not called and its properties does not take values

I have two similar beans. They are set to be called in a ScheduledTimerTask.
But one is working fine, the other is not! Here are these two configurations:
<!-- Clear Orders By Sessions -->
<bean id="clearExpiredSessionOrdersTask" class="com.datx.timers.ClearExpiredSessionOrdersTask" autowire="byName">
<property name="period" value="00:02:10"/>
</bean>
<bean id="clearExpiredSessionOrdersTaskInvoker"
class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
<property name="targetObject" ref="clearExpiredSessionOrdersTask" />
<property name="targetMethod" value="doTask" />
</bean>
<bean id="clearExpiredSessionOrdersTaskTimer" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask" ref="clearExpiredSessionOrdersTaskInvoker" />
<property name="delay" value="1000" /><!-- In miliseconds -->
<property name="period" value="130000" /><!-- In miliseconds -->
</bean>
<!-- Clear Orders By Sessions -->
This is the one which is working. My class is com.datx.timers.ClearExpiredSessionOrdersTask in the first line.
The other bean is set like this:
<!-- DocumentScheduleTask -->
<bean id="documentSchaduleTask" class="com.datx.timers.DocumentSchaduleTask" autowire="byName" init-method="init">
<property name="period" value="00:02:10"/>
</bean>
<bean id="documentSchaduleTaskInvoker"
class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
<property name="targetObject" ref ="documentSchaduleTask" />
<property name="targetMethod" value="doTask" />
</bean>
<bean id="documentSchaduleTaskTimer" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask" ref="documentSchaduleTaskInvoker" />
<property name="delay" value="1000" /><!-- In miliseconds -->
<property name="period" value="130000" /><!-- In miliseconds -->
</bean>
<!-- DocumentScheduleTask -->
Do you see the similarities? Again the first line is my class.
An this is my DocumentScheduleTask class:
public class DocumentSchaduleTask{
private String period;
public init(){
System.out.println("Test");
}
public void doTask(){
//This method is called at a specific time
}
public void setPeriod(String period){
this.period = period;
}
public String getPeriod(){
return this.period;
}
}
The rest of these configurations are the same. But in the second one the period property does no take value. And its init method is not called. What are these implying?
Why would have caused this? Where should I look for? Do you see any differences at all?
My one concern about this difference is init method in the second configuration. AFAIK init called after properties set to bean, so maybe it is possible that code in your init method clear that value. Please, add sources of your init method for DocumentSchaduleTask.
And, maybe, your typo Sch a duler causes some problems as you autowire by name.

Programmatically set property of bean

I am trying to figure out how I can adjust the "period" property of the "destroyWorldTask" bean that is defined like this in my list of beans. Is this possible? What is the proper way to do this?
<bean id="mytimerfactory"
class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="daemon" value="true"/>
<property name="myTimerTasks">
<list>
<bean class="org.springframework.scheduling.timer.ScheduledTimerTask" id="destroyWorldTask">
<property name="delay" value="100"/>
<property name="period" value="10000/>
<property name="runnable">
<bean class="com.scene7.is.util.SafeRunnable">
<constructor-arg ref="destroyWorld"/>
</bean>
</property>
</bean>
</list>
</property>
</bean>
There are two possible answers:
1. If you want the "period" property be set somewhere in the program, you don't need to set in the context configuration. (Which I think not suitable for you, as you are using a spring class, not yours).
2. Extend from org.springframework.scheduling.timer.ScheduledTimerTask and make your edition of the class, something like:
public MyTimeScheduledTimerTast extends ScheduledTimerTask{
//...
}
and set that property in your program. (Now it's in your hand)
Then update your context configuration like this:
<bean id="mytimerfactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="daemon" value="true"/>
<property name="myTimerTasks">
<list>
<bean class="myPackage.MyScheduledTimerTask" id="destroyWorldTask">
<!-- Set those properties that are not set in your program -->
</bean>
</list>
</property>
</bean>

how to extend a list in spring config

I have defined a with some "common" values. How can I extend the common list by additional values to various new beans?
<util:list id="myCommonList" list-class="java.util.LinkedList">
<bean .../>
<bean .../>
<bean .../>
<bean .../>
</util:list>
<bean id="extension" parent="myCommonList">
<bean ref="additionalValue"/>
</bean>
Will this overwrite the list or extend it?
You can do it, but not using <util:list>, which is just a convenience syntax. The container does provide a "collection merging" function, but you have to use the "old" style:
<bean id="parent" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<value>X</value>
</list>
</property>
</bean>
<bean id="child" parent="parent" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list merge="true">
<value>Y</value>
</list>
</property>
</bean>
Based on skaffman's answer, you can achive this way:
<util:list id="parent">
<value>X</value>
</util:list>
<bean id="child" parent="parent" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list merge="true">
<value>Y</value>
</list>
</property>
</bean>
To append list2's elements to list1 use the following spring config.
<util:list id="list1">
<value>1</value>
<util:list>
<util:list id="list2">
<value>3</value>
<value>5</value>
<util:list>
<bean
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="list1" />
<property name="targetMethod" value="addAll" />
<property name="arguments" ref="list2" />
</bean>
According to this JIRA; there is no trivial solution for this (currently, but hopefully in 3.1 there will be), though there are several workarounds; e.g. this one.
Today I was having this issue too. For me the acceptable solution was to use SpEL and while SpEL doesn't supports multiple statements - create two auxiliary classes that appends lists.
Context might be implemented like this:
<util:list id="list1">
<value>str1</value>
<value>str2</value>
</util:list>
<util:list id="list2">
<value>str3</value>
<value>str4</value>
</util:list>
<bean ...>
<property name="propertyThatRequiresMergedList"
value="#{ new x.y.springs.StringListsMerger().merge(#list1, #list2) }" />
</bean>
And classes:
package x.y.springs;
import java.util.List;
public abstract class ListsMerger<T extends List> {
public T merge(T ... lists) {
T container = createContainer();
for (T list : lists) {
container.addAll(list);
}
return container;
}
public abstract T createContainer();
}
package x.y.springs;
import java.util.ArrayList;
import java.util.List;
public class StringListsMerger extends ListsMerger<List<String>> {
#Override
public List<String> createContainer() {
return new ArrayList<String>();
}
}
You can overwrite or add any other bean in this list by following the below snippet.
For example: this is your bean which needs to be injected in the AAA util:list mentioned below.
<bean id = "BBB" class=""/>
<util:list id="AAA"/>
<bean id="AAAListMergeDirective" depends-on="AAA"
parent="listMergeDirective" >
<property name="add" ref="BBB" />
</bean>

Resources