Multiple property file - spring

How to handle multiple property files in spring with placeholderconfigurer?
I have an application context in Common project with following bean entry:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties" />
</bean>
And in Service layer project I have another application context file with this bean entry:
<beans:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<beans:property name="location" value="classpath:kestrel.properties" />
</beans:bean>
The entries in property file are like :
database proprties:
URL= xxx
USERNAME = xxx
PWD = xxx
kestrel.properties:
mediacast.url = xxx
With these setting, when I start my tomcat server I get expection like:
Could not resolve placeholder 'mediacast.url' from kestrel.properties - property file.
Thanks in advance for any help!

On my application, I do that:
<bean id="envPropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>one/path/to/file</value>
<value>another/path/to/file</value>
</list>
</property>
</bean>

Related

How can I turn contents of CSV file into XML using Spring batch?

I'm using Spring Batch 3.0.8.RELEASE. I want to read the contents of a CSV file and turn it into XML. I am familiar with reading CSV files in Spring Batch, but the behavior I've seen is "chunk" oriented processing....one line at a time, and I'm not sure this default behavior will work for me here.
Here is the CSV sample:
,WT4RT,AIG-00,694304F,9/1/2017,9/30/2017,"6,975.00",AIG-00201709,10/10/2017,USD,MC
,WT4RT,AIG-00,694317E,9/1/2017,9/30/2017,"2,583.80",AIG-00201709,10/10/2017,USD,MC
,WT4RT,AIG-00,694304G,9/1/2017,9/30/2017,"17,600.00",AIG-00201709,10/10/2017,USD,MC
,WT4RT,AIG-00,694304G,9/1/2017,9/30/2017,740,AIG-00201709,10/10/2017,USD,MC
I need to turn this data into the following XML format:
<?xml version="1.0" encoding="UTF-8"?>
<BillingAndCosting version="1.0">
<ControlArea>
<SenderId>CMS-BILLING-100</SenderId>
<WaterMark>92030293829329392030232</WaterMark>
<RecordCount>2</RecordCount>
<TimeStamp>2001-12-17T09:30:47-05:00</TimeStamp>
<DataFileName>String</DataFileName>
</ControlArea>
<DataArea>
<CustomerAccount>
<ExternalKey>1001</ExternalKey>
<ExternalSource>HBVenture</ExternalSource>
<BillingData>
<ReferenceID>0</ReferenceID>
<BillingInvoiceNumber>2000016</BillingInvoiceNumber>
<BillingInvoiceDate>2017-01-31T06:42:07.000Z</BillingInvoiceDate>
<BillingPeriodFromDate>2017-01-01T06:42:07.000Z</BillingPeriodFromDate>
<BillingPeriodThruDate>2017-01-31T06:42:07.000Z</BillingPeriodThruDate>
<BillingInvoiceType>NEW</BillingInvoiceType>
<BillingAmount CurrencyID="USD">1290.39</BillingAmount>
<InvoiceItem>
<CategoryCode>res-group</CategoryCode>
<TaxCategoryID>C2</TaxCategoryID>
<InvoiceItemAmount CurrencyID="USD">1290.39</InvoiceItemAmount>
<ProductID>694601F</ProductID>
<ISVUID>1</ISVUID>
</InvoiceItem>
</BillingData>
<BillingData>
<ReferenceID>0</ReferenceID>
<BillingInvoiceNumber>2000017</BillingInvoiceNumber>
<BillingInvoiceDate>2017-01-31T06:42:07.000Z</BillingInvoiceDate>
<BillingPeriodFromDate>2017-01-01T06:42:07.000Z</BillingPeriodFromDate>
<BillingPeriodThruDate>2017-01-31T06:42:07.000Z</BillingPeriodThruDate>
<BillingInvoiceType>NEW</BillingInvoiceType>
<BillingAmount CurrencyID="USD">590.39</BillingAmount>
<InvoiceItem>
<CategoryCode>gateway_resource_group</CategoryCode>
<TaxCategoryID>C2</TaxCategoryID>
<InvoiceItemAmount CurrencyID="USD">590.39</InvoiceItemAmount>
<ProductID>694601F</ProductID>
<ISVUID>1</ISVUID>
</InvoiceItem>
</BillingData>
I'm showing only a portion of the XML for brevity. The thing I don't know is: how to use Spring Batch to read the entire CSV file to populate an Object that I can then send to the XML Marshaller for converting into XML.
Can it be done with Spring batch, or do I have to 'roll my own'?
We use StaxEventItemWriter as ItemWriter (example below)
<bean id = "xmlItemWriter"
class = "org.springframework.batch.item.xml.StaxEventItemWriter">
<property name = "resource" value = "file:my_path_to_xml.xml" />
<property name = "marshaller" ref = "reportMarshaller" />
<property name = "rootTagName" value = "BillingAndCosting" />
</bean>
<bean id = "reportMarshaller"
class = "org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name = "classesToBeBound">
<list>
<value>BillingAndCosting</value>
</list>
</property>
</bean>
You can use FlatFileItemReader for reading the CSV file. Follow the below sample code:
ItemReader reads a complete line one by one from input csv file. FlatFileItemReader is used for reading the csv file.
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="fieldSetMapper">
<!-- Mapper which maps each individual items in a record to properties in POJO -->
<bean class="com.websystique.springbatch.ExamResultFieldSetMapper" />
</property>
<property name="lineTokenizer">
<!-- A tokenizer class to be used when items in input record are separated by specific characters -->
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value="|" />
</bean>
</property>
</bean>
</property>
</bean>
XML ItemWriter which writes the data in XML format.
<bean id="xmlItemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
<property name="resource" value="file:xml/examResult.xml" />
<property name="rootTagName" value="UniversityExamResultList" />
<property name="marshaller">
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.websystique.springbatch.model.ExamResult</value>
</list>
</property>
</bean>
</property>
</bean>
You should also go through the official Spring docs Spring Docs

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!!!

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

Is it possible to alias bean class names in Spring?

I have a string property which looks similar to the following example:
<property name="mappingData">
<list>
<bean class="com.company.product.longNamingStandard.migration.extractor.FieldMapping">
<property name="elementName" value="entitlement.user"/>
<property name="mapping" value="DocUsers"/>
</bean>
<bean class="com.company.product.longNamingStandard.migration.extractor.FieldMapping">
<property name="elementName" value="entitlement.contributor"/>
<property name="mapping" value="DocContributors"/>
</bean>
</list>
</property>
The long class name(s) effect readability & also create a refactoring overhead.
Is it possible to alias the class name and use a short name to declare the beans? Or is there an alternate best practice I'm missing?
Probably a bit late for you, but hopefully useful for others:
You can use parent beans to accomplish this.
First declare a parent bean as a template:
<bean id="FieldMapping" class="com.company.product.longNamingStandard.migration.extractor.FieldMapping"/>
Then use it elsewhere, using the parent attribute.
<property name="mappingData">
<list>
<bean parent="FieldMapping">
<property name="elementName" value="entitlement.user"/>
<property name="mapping" value="DocUsers"/>
</bean>
<bean parent="FieldMapping">
<property name="elementName" value="entitlement.contributor"/>
<property name="mapping" value="DocContributors"/>
</bean>
</list>
</property>
Please note my convention here is to use upper case id's here for the parent template beans.
each <bean/> comes with an attribute of name and id to help you reference those beans later in your configuration.
I would suggest using the id for declaring the bean.
your config could look like:
<bean id="fooBean" class="com.example.foo"/>
<bean id="barBean" class="com.example.bar"/>
<list>
<ref>fooBean</ref>
<ref>barBean</ref>
</list>
You may try to represent your mapping in some short form, and then convert it to the list of FieldMappings. For example, mappings from your snippet may be represented as a map.
As a theoretic exercise in Spring 3 you can do this with Spring Expression Language (if FieldMapping has the apropriate constructor):
<util:map id = "m">
<entry name = "entitlement.user" value = "DocUsers" />
<entry name = "entitlement.contributor" value = "DocContributors" />
</util:map>
...
<property name = "mappingData"
value = "#{m.![new com.company.product.longNamingStandard.migration.extractor.FieldMapping(key, value)]}" />
If this expression is too obscure, you may implement a FactoryBean to take a short form of your mapping data (for example, a map, as in this example) and return a configured list of FieldMappings:
<property name = "mappingData">
<bean class = "FieldMappingListFactoryBean">
<property name = "mappings">
<map>
<entry name = "entitlement.user" value = "DocUsers" />
<entry name = "entitlement.contributor" value = "DocContributors" />
</map>
</property>
</bean>
</property>
However, if your field mappings are some kind of reusable DSL, you may try to think about implementing a namespace extension.
I found a way to simulate an effect similar to a "import com.Foo;" in java code. The best option I could find was to use a PropertyPlaceholderConfigurer with local properties defined. Using your example, here's the configuration that you would put at the top of your spring config file to define a "class_FieldMapping" property:
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<description>Define properties equivalent to "import foo;" in java source</description>
<property name="properties">
<props>
<prop key="class_FieldMapping">com.company.product.longNamingStandard.migration.extractor.FieldMapping</prop>
</props>
</property>
</bean>
Then, you can use that property within your beans:
<property name="mappingData">
<list>
<bean class="${class_FieldMapping}">
...
</bean>
<bean class="${class_FieldMapping}">
...
</bean>
</list>
</property>
This has the benefit that use can also use it for things where you actually need the class name, and can't reference an instance of an object:
<util:constant static-field="${class_FieldMapping}.MYSTATICVAR" />
Why not declare those inner beans as separate top-level beans with their own names, and then reference them in the list ?
If I use PropertyPlaceholderConfigurer it leads to several exceptions in debug log. It works, but it seems it doesn't work on the first try.

Resources