How to fill map, configured with spring, from properties file - java

I have built a small app that reads an Excel file and creates all the necessary SQL statements for me. Excel file is manipulated by customers from time to time.
The first line of the Excel file includes a title I need to translate into integers when reading the lines. For example, the title "english" needs to be translated into "30" before I generate the SQL statements. (Just some internal definitions). (You could compare it with DNS - Human readable domain name into IP-Address mapping)
Currently I do the mapping manually, but I want to get rid of this step with a tiny Spring configuration. Because the headlines are not fixed, it is necessary to read the headline information from a properties file.
I found something like this:
<bean class="java.util.HashMap" id="exampleMapping">
<constructor-arg index="0">
<map>
<entry key="theKey" value="theValue"/>
<entry key="otherKey" value="otherValue"/>
</map>
</constructor-arg>
</bean>
Which seems to work quite well. But the Spring configuration is compiled into a jar. So my first choice (if possible) would be to externalize the key value pairs into a properties file.

You're in luck, because the Properties class implements Map!
Just define the properties bean like so:
<util:properties id="myProps" location="classpath:myProps.properties" />
(Don't forget to import the Spring util namespace)

Related

Java spring bean wont load xml config file

I want to use some values that are stored in a config file. Im trying to load in the config file and use it with a bean. Im new to spring and beans so im not really sure the best implementation for this. But i want to use the values as constructor arguments to the bean. I have a packet beans with the xml file beans in it. And in the same map "src/java/main" is the other packet with the xml file credentials.config.
/TwitterDownload/src/main/java/TwitterProjectNTS/beans/beans.xml qualified name for beans
/TwitterDownload/src/main/java/TwitterProjectNTS/TwitterDownload/credentials.config qualified name for credebtials.config
<import
resource="/TwitterDownload/src/main/java/TwitterProjectNTS/TwitterDownload/credentials.config" />
<bean id="TwitterConfigurationStartupSettings"
class="">
<constructor-arg
value=""></constructor-arg>
<constructor-arg
value=""></constructor-arg>
<constructor-arg
value=""></constructor-arg>
<constructor-arg
value=""></constructor-arg>
</bean>
I have read many articles about this but have not got a good understanding for how to really get this to work. Seems like there are many ways to read and use the values from the file.
Grateful for answears

Spring batch dynamic file writer

Does spring batch provide any dynamic/generic file writers? For example, if i have multiple requirements of generating a file and i have one view created for each purpose, all i want to do is specify the view name and i want spring-batch to extract the data from the view to a flat file with column headings. This is as simple as if you have used dbviz or sql developer, just export the result of a query to a file.
Recently i had 4 different requirements of extracting data to file, and i have repeated the config file and created a record bean and record mapper to map the bean to the columns of view for each file. Rather than repeating this entire process every time, i am looking to see if Spring batch or any other java frameworks provides a generic approach to extracting a file based on the table and its columns without writing result set mappers or dealing with field extractors.
I can build a generic spring batch file extractor but wanted to check if spring-batch already does that, which seems like a basic thing?
Also if i create a generic extractor then the attributes of the bean will be kinda dynamic based on the columns names of the view. So in that scenario, if i have about 50 columns i dont want to specify each attribute in fieldExtractor, i want all the attributes to be extracted. Currently i am specifying attributes in spring config as given below, but i don't want to spefiy the attribute names. I just want to say extract all attributes. Is that possible?
<bean id="CsvItemWriter" class="some.class.FileWriter" scope="step">
<property name="resource" value="file://#{jobParameters['file.name']}"/>
<property name="shouldDeleteIfExists" value="true" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="delimiter">
<util:constant static-field="org.springframework.batch.item.file.transform.DelimitedLineTokenizer.DELIMITER_TAB" />
</property>
<property name="fieldExtractor"> <bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names" value="name.last, name.first, name.middle, birthDate, gender, homePhone, cellPhone"/>
</bean>
</property>
</bean>
</property>
In case some one needs it, i found a similar question in SO that was difficult to find. I am using columnMapRowMapper as mentioned here

Spring reference a property from a property bean

I have created a spring configuration file that works well.
My next step was to separate user configuration properties from system properties.
I have decided to create additional xml file with beans that will be configured by the user.
I had problem to create few such logical beans encapsulating properties that will be used by real class beans:
I have found over the net an option to reference proprieties in such way:
UserConf.xml
<bean id="numberGuess" class="x...">
<property name="randomNumber" value="5"/>
<!-- other properties -->
</bean>
SystemConf.xml
<import resource="UserConf.xml" />
<bean id="shapeGuess" class="y...">
<property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>
<!-- other properties -->
</bean>
But my problem is that i need x... class to be something logical that shouldn't be initialized at all, and i don't want it to disclose any info of the class hierarchy of the system since it should be only in use configuration xml file.
Solution1 is to create a Java object representing this proprieties:
public class MyProps(...)
and add a bean parent in the spring system configuration:
<bean id="MyProps" class="path to MyProps"/>
in the user side change the previous bean to be:
<bean id="numberGuess" parent="MyProps">
<property name="randomNumber" value="5"/>
<!-- other properties -->
</bean>
Solution2 is to use flat configuration file just like Database.props, and load it using factory.
Solution3 is to use Spring Property Placeholder configuration to load properties from XML properties file (e.g. example), but here i simply don't know how to get a more complex nested structure of properties (properties need to be separated by different logical names, e.g. minNumber will be defined both under xAlgo and y algo).
I don't like to create new Java class only to deal with this problem or to move my user configuration to a flat props file (i need the xml structure), is their any other solution??
I will answer my own question, since it looks as the best solution for me (and much more simplistic than was suggested)
I will use PropertiesFactoryBean to do the work for me:
e.g.
UserConf.xml
<bean id="numberGuess" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="randomNumber">3</prop>
<!-- other properties -->
</bean>
SystemConf.xml
<import resource="UserConf.xml" />
<bean id="shapeGuess" class="y...">
<property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>
<!-- other properties -->
</bean>
First if you don't know about the property place holder you should take a look at that. Also #Value("${some.property:defaultvalue}") is something you should look at.
Second the word configuration is ambiguous in Spring. Spring uses this word but they mean developer configuration not user configuration. Despite what people say or think Spring is not a configuration engine.
I'm not sure what your trying to do but you should be aware that your configuration will not be adjusted at runtime which is frequently needed for something like "user" configuration. So most people write their own configuration layer.
Another thing you should take a look at is not using the XML configuration and instead use Java Configuration which will give you way more flexibility.

Determining properties available for Spring Beans?

In the Spring Framework, how do you determine what "properties" and other related values are available to be set in the context.xml file(s)? For example, I need to set the isolation level of a TransactionManager. Would that be:
<property name="isolation" value="SERIALIZABLE" />
<property name="isolation_level" value="Isolation.SERIALIZABLE" />
or some other values?
Each bean represents a class, which you can easily find by class="" attribute. Now you simply open JavaDoc or source code of that class and look for all setters (methods following setFooBar() naming convention). You strip set prefix and un-capitalize the first character, making it fooBar. These are your properties.
In your particular case you are probably talking about PlatformTransactionManager and various implementations it has.
Putting the properties into . properties file is a good way of handling.
First define a properties file in your project structure. It is better to put .properties file with the same directory as spring applicationContext.xml.
Your properties file may seem like this :
isolation = "SERIALIZABLE"
isolation_level = Isolation.SERIALIZABLE
You can access this properties file by defining a spring bean like :
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:YourProperties.properties"/>
</bean>
Finally you can access these properties inside Spring beans like :
<bean id="BeanName" class="YourClass">
<property name="PropertyName1" value="${isolation}"/>
<property name="PropertyName" value="${isolation_level}"/>
</bean>
There is another way to inject these values using annotations.

In Spring can you alter property placeholder values using a BeanDefinitionDecorator?

I have a BeanDefinitionDecorator that makes modifications to properties that a user would set on a bean. It works fine; except if the bean is using placeholders. I am trying to find a strategy to modify those values while still have access to the original value at runtime. An example of what this would look like in XML:
<bean id="bean">
<property name="jdbcUrl" value="${jdbc.url}" />
<d:spyDecorator />
</bean>
I know that user would be writing the jdbcUrl property as "jdbc:myDatabase". What I want to do is change their property to "jdbc:spy:myDatabase". This is easy if they are just using string literals for the property value, but if they are using property placeholders I am not sure how to change the value -- because I need the original value in order to supply the new value. They key is to keep the property rewriting transparent to the user.
Are there any possible solutions for this?
I think your namespace handler can register a BeanFactoryPostProcessor (implementing Orderer with order = Integer.MAX_VALUE to be the last post processor applied). Then your BeanDefinitionDecorator will register the beans being decorated for processing with that post processor (implement it in the post processor somehow), and post processor will apply the actual property modification to that beans.
You can use PropertyPlaceholderConfigurer to substitute property values for placeholders in bean properties, aliases, and other places. Note that the replacements happen AFTER the bean definitions have been loaded, so this mechanism does not apply to <import> elements
For example:
...
<bean id="ppc"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:build.properties</value>
<value>classpath:default-emmet-substitution.properties</value>
<value>classpath:default-danno-substitution.properties</value>
<value>classpath:default-dannotate-substitution.properties</value>
<value>classpath:substitution.properties</value>
</list>
</property>
</bean>
...
For more information refer to this section of the Spring Framework docs.
EDIT - I guess from your comment you are already familiar with how placeholder replacement works, and are using PropertyPlaceholderConfigurer to do the replacements. So now you need to choose between these strategies, or some combination:
Do the placeholder replacements yourself in your custom BeanDefinitionDecorator. That would work, though you'd be duplicating a lot of code.
Have the custom BeanDefinitionDecorator modify the placeholder names to different ones that will pull in different values; e.g. "${jdbc.url}" becomes "${spy.jdbc.url}".
Extend the PropertyPlaceholderConfigurer class to modify the substituted property values; i.e. override convertProperty or convertProperties. That has the potential problem that all placeholders will get the modified values ... not just the ones in beans that you have decorated.
Create a new PropertyResourceConfigurer class to substitute different property values depending on the context. Essentially, the processProperties needs to work like the method does in a PropertyPlaceholderConfigurer, but do something different if it sees bean properties or whatever that tell it to do the "spy" substitution.
A combination of 2) and 3) looks the most promising.

Categories