I'd like to inject a java.util.Properties object into another bean through XML config. I have tried the solution listed here without success, presumably because the bean is being injected before the property resolution occurs. Is there a way that I can force the java.util.Properties object to be resolved before being injected to my class?
Below is the trimmed/edited version of what I have. PropertiesConsumingClass does receive the merged, but unresolved properties of a, b, and c properties files.
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="allProperties" />
</bean>
<bean id="allProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="propertiesArray">
<util:list>
<util:properties location="classpath:a.properties" />
<util:properties location="classpath:b.properties" />
<util:properties location="classpath:c.properties" />
</util:list>
</property>
</bean>
<bean class="PropertiesConsumingClass">
<constructor-arg index="0" ref="allProperties" />
</bean>
Your example doesn't work because what Spring calls a property isn't the same thing as what Java calls a property. Basically, a Spring property lives in a <property> tag, and this is what gets resolved by PropertyPlaceholderConfigurer. You can also use property placeholders inside #Value annotations. Either way you have a string with ${} placeholders that get resolved, possibly the string is converted to the correct type, and injected into your bean.
java.util.Properties are used to resolve placeholders in Spring properties, but they aren't considered for resolution themselves. Any properties in a., b., or c.properties will be substituted into Spring property placeholders, but PropertyPlaceholderConfigurer doesn't know or care if the values it gets from those files have ${} in them.
Now, Spring Boot does resolve placeholders inside its config files, but it has special sauce to accomplish that. It's also a very opinionated library that wants to control your app's lifecycle and does lots of magical things behind the scenes, so it's very hard to adopt or drop except at the very beginning of a project.
Related
I have the following definition:
<bean id="logger" factory-method="createLog" scope="prototype" class="com.test.beans.LogBean" ></bean>
<bean id="aone" class="com.test.beans.AggregationOne">
<property name="log" ref="logger"></property>
</bean>
<bean id="atwo" class="com.test.beans.AggregationTwo">
<property name="log" ref="logger"></property>
</bean>
Is it possible to recognize for which object (aone or atwo) bean 'logger' is being created?
Why I'm asking: in a legacy application I have one log instance for all classes. I want to change level for some packages, but can't do that (except using filters, what I don't want). For that purpose I want to utilize some spring magic, if it exists for that case )
I don't think it can be done this way. What you could try is a BeanPostProcessor implementation which detects common logger object in beans and replaces it with a specific one.
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.
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 my spring batch project I can do something like this:
<bean id="exampleTasklet" class="my.custom.Tasklet">
<property name="message" value="job parameter value: #{jobParameters['arg1']}"/>
</bean>
and the message property will have a value taken from the spring batch job parameters. However, the value that I actually want to assign is very large and I don't want to put it in the xml file. I know this syntax doesn't work, but I would like to do something like:
<bean id="exampleTasklet" class="my.custom.Tasklet">
<property name="message" read-value-from-file="/path/to/file.txt"/>
</bean>
and that file would contain the line "job parameter value: #{jobParameters['arg1']}" which spring will parse as if the file content was in a value="" attribute.
Is there a nice way to do this?
I think what you are looking for is a PropertyPlaceholderConfigurer.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/path/to/file.properties" />
<property name="placeholderPrefix" value="#{" />
<property name="placeholderSuffix" value="}" />
</bean>
This is run by Spring as a bean processor and will attempt to resolve placeholder tokens. There is a default instance that will resolve against system properties, using this notation: ${propertyname}. For your notation, you would need to specify the placeholderPrefix/Suffix. When there are multiple bean processors, the order is determined by the order property. By default, if a processor fails to resolve a placeholder, execution fails, but this can be altered by setting ignoreUnresolvablePlaceholders. Since the mechanism is property driven, you probably want to consider a notation like:
<property name="message" value="job parameter value: #{jobParameters.arg1}"/>
Or, if what you're trying to convey is that arg1 is also a parameter, you might try:
<property name="message" value="job parameter value: #{jobParameters.${arg1}}"/>
Spring loops over the bean processors until no replacements are performed, or an exception is raised. So defining a property as ${something.${orOther}} is valid.
I would suggest you to use a String as file name and in your bean open that file.
I'm not sure if I get your problem right. I'm just suggesting something like Spring MessageBundle
Something like this:
<bean id="exampleTasklet" class="my.custom.Tasklet">
<property name="messagePath" location="/path/to/file.txt"/>
</bean>
And in your exampleTasklet read the file and do your thing (I'm not sure what it is)
If anybody came here to do something like this from a properties-file:
If you want a property from a .properties-file to appear in the JobParameters, you won't find ready-to-use solution. You can do the following:
Wrap a bean around your properties file.
Pass this bean to another one which has access to the JobParameters and can pump the properties from the file into that class.
Then you should be able to access your properties with Spring's Expression Language and do something like:
<bean id="myBean" class="my.custom.Bean">
<property name="prop" value="#{jobParameters['arg1']}"/>
</bean>
Alternatively, I think the solution proposed by Devon_C_Miller is much easier. You don't have the properties in your JobParameters then. But if the replacement in the XML configuration is the only thing you want, you only have to change your placeholders to:
${myPropFromFile}
Happy batching, everyone ;-)
I have three apps in a Spring 2.5 managed project that share some code and differ in details.
Each application has a property (java.lang.String) which is used before the application context is built.
Building the app context takes some time and cannot happen first. As such, it's defined in each individual application. This property is duplicated in the context definition since it is also needed there. Can I get rid of that duplication?
Is it possible to inject that property into my application context?
Have a look at PropertyPlaceholderConfigurer.
The Spring documentation talks about it here.
<bean id="myPropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:my-property-file.properties"/>
<property name="placeholderPrefix" value="$myPrefix{"/>
</bean>
<bean id="myClassWhichUsesTheProperties" class="com.class.Name">
<property name="propertyName" value="$myPrefix{my.property.from.the.file}"/>
</bean>
You then have reference to that String to anywhere you'd like in your application context, constructor-arg, property etc.
With spring 3.0 you have the #Value("${property}"). It uses the defined PropertyPlaceholderConfigurer beans.
In spring 2.5 you can again use the PropertyPlaceholderConfigurer and then define a bean of type java.lang.String which you can then autowire:
<bean id="yourProperty" class="java.lang.String">
<constructor-arg value="${property}" />
</bean>
#Autowired
#Qualifier("yourProperty")
private String property;
If you don't want to deal with external properties,you could define some common bean
<bean id="parent" class="my.class.Name"/>
then initialize it somehow, and put into common spring xml file, lets say common.xml. After that, you can make this context as a parent for each or your apps - in your child context xml file:
<import resource="common.xml"/>
and then you can inject properties of your parent into the beans you're interested in:
<bean ...
<property name="myProperty" value="#{parent.commonProperty}"/>
...
</bean>