constructor-arg ref from properties in spring - java

I have bean which has to be binded at run time.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="${requiredBean:mysql}"/>
</bean>
<bean id="mysql" class="xxx.xxx.xxxxxx">
</bean>
<bean id="mongo" class="xxx.xxx.xxxxxx">
</bean>
In the property file I added the property
requiredBean=mongo
But due to some reason the requiredBean from the properties file is not picked up by the spring (The properties file is configured correctly and all other properties are loading properly except for this one).
I just want to know if the syntax that I used for declaring the arg for constructor aa ref is right or is there any other way to declare it.
Pls help me to resolve this.
Let me know if the question is not clear.

if you are sure (as you already mentioned in the content of .properties) that you are mentioning the right property(no spelling error), then problem is something else, and not the property itself. Try removing the default value . It must throw exception like :::: java.lang.IllegalArgumentException: Could not resolve placeholder 'XYZ' in string value "${XYZ}". If it does not throw this exception, issue is not related to this bean at all.

Related

Inject Resolved Properties Object to Another Bean

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.

What exactly do the following SpEL expression?

I have some doubt about what exactly do these 3 Spring SpEL example:
1) FIRST EXAMPLE:
<bean id="rewardsDb" class="com.acme.RewardsTestDatabase">
<property name="keyGenerator" value="#{strategyBean.databaseKeyGenerator}" />
</bean>
It seems to me that this code snippet injet an inner property named databaseKeyGenerator (that is inside the strategyBean bean). So in this case SpEL is used to access to a specific bean property in the classica OO logic. Is it true?
2) SECOND EXAMPLE:
<bean id="strategyBean" class="com.acme.DefaultStrategies">
<property name="databaseKeyGenerator" ref="myKeyGenerator"/>
</bean>
It seems to me that SpEL is not used, or am I missing something?
3) THIRD EXAMPLE:
<bean id="taxCalculator" class="com.acme.TaxCalculator">
<property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>
</bean> Equivalent
It is used to inject a property value taken from a property file
Is it correct or I a missing something or am I misinterpreting the SpEL logic?
The first and second examples come together. The second actually uses no SpEL at all. Its sole purpose is to help understand the first one. So you are not missing something regarding the first two.
As for the third one, systemProperties is a predefined variable and you use it to access system properties. Except from the standard VM system properties you can also access those that you pass with -D when starting the application.
You can access a property file the same way, after creating a bean to reference them, by using the bean id instead of systemProperties. For example
<util:properties id="appProps" location="classpath:application.properties" />
and then
<property name="propOne" value="#{appProps['some.property'] }"/>

Spring context:property-placeholder for a boolean value

I am working on an application where I have two classes both implementing a common interface. So in time of bean declaration, I am going to mark one of them primary in my app-context.xml file. I can achieve this by simply declaring the primary bean like this:
<bean id="oracleImpl" class="com.me.dao.OracleImpl" primary="true">
</bean>
Now I don't want to hard code which of the beans is going to be the primary bean, rather want to read the true/false value from a properties file. So I went like this:
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="oracleImpl" class="com.me.dao.OracleImpl" primary="${oracle.primary}">
</bean>
<bean id="pgsqlImpl" class="com.me.dao.PgsqlImpl" primary="${pgsql.primary}">
</bean>
The values of oracle.primary and pgsql.primary are defined in the file jdbc.properties along with other jdbc (non-boolean) properties.
But it doesn't work and says, "'${oracle.primary}' is not a valid value for 'boolean'"
I have a feeling it is something to do with the xsd validators. Browsing through this site and google gave me this much idea, but got no real solution. Can any body help?
This will not work.
As of 3.2.5.RELEASE only the following bean definition elemets support property placeholder:
parent name
bean class name
factory bean name
factory method name
scope
property values
indexed constructor arguments
generic constructor arguments
See the BeanDefinitionVisitor's visitBeanDefinition method for the details. This method is used by the PlaceholderConfigurerSupport.
I would recommend you to create a feature request in the spring issue management system.
PS: if you create an issue please add a comment to the issues url.

How do I load a bean value from a file with job parameter substitution?

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 ;-)

Spring: Get inline bean by name

I would like to get inner bean by it's name. Is it possible with Spring API?
Right now I'm using such Spring 2.5 API
ConfigurableApplicationContext.getBean(String paramString)
Example of XML:
<bean id="parent" parent="t_Parent">
<property name="items">
<bean id="child" parent="t_Child">
<property name="ABC" value="test"/>
</bean>
</property>
</bean>
I would like to get inner (t_Child) bean by id "child". E.g. ConfigurableApplicationContext.getBean("child"). Spring can't find such bean (because it's inner). At the same time .getBean("parent") works fine.
Any thoughts?
You can't.
From the docs:
A element inside the or elements is used to define a so-called inner bean. An inner bean definition does not need to have any id or name defined, and it is best not to even specify any id or name value because the id or name value simply will be ignored by the container.
If you need it like that, define it as a regular bean.
You can't, but you can create you inner bean outside (so it's no longer an inner bean...) and then reference it inside the property:
<bean id="child" parent="t_Child">
<property name="ABC" value="test"/>
</bean>
<bean id="parent" parent="t_Parent">
<property name="items" ref="child"/>
</bean>
Apart from the other (mostly valid) answers and solutions, I guess the spring way would be to use the BeanWrapper interface:
final BeanWrapper bw =
new BeanWrapperImpl(applicationContext.getBean("parent"));
Object innerBean = bw.getPropertyValue("child");
But I guess that implies that there must be a getter for the property (not only a setter).
Reference:
BeanWrapper (javadoc, 2.5 version)
Bean manipulation and the BeanWrapper (reference, 2.5 version)
If you move up to Spring 3.x, you should be able to do this with the Spring Expression Language. There are examples of directly referencing a bean property from another property (like in link text). The code to do this from Java would be somewhat similar, although I can't find an exact example of this scenario.
However, I would say that if you're trying to use "getBean()", you're doing something wrong. You could just as easily use the SpEL in your context to define a bean or a bean property that references that inner bean.

Categories