I am getting Circular reference error if my placeholder key starts with "database"
This config gives error.
<bean id="paymentTransactionLogMessageDecoratorDao"
class="com.gsicommerce.payment.dao.PaymentTransactionLogMessageDecoratorDao">
<constructor-arg ref="paymentTransactionLogMessageDao"/>
<constructor-arg value="${database.payments.logging.enabled}"/>
</bean>
Error: Circular placeholder reference
'database.payments.logging.enabled' in property definitions
When we change the key name like this,
<bean id="paymentTransactionLogMessageDecoratorDao"
class="com.gsicommerce.payment.dao.PaymentTransactionLogMessageDecoratorDao">
<constructor-arg ref="paymentTransactionLogMessageDao"/>
<constructor-arg value="${payments.database.logging.enabled}"/>
</bean>
this works. Do we have any reserve key words ("database") ?
As you can see, its a constructor injection and the property name is completely different.
public paymentTransactionLogMessageDecoratorDao(PaymentTransactionLogPersistenceServicetransactionLogMessageDao,
boolean databaseLoggingEnabled) {
this.transactionLogPersistenceService = transactionLogMessageDao;
this.databaseLoggingEnabled = databaseLoggingEnabled;
}
Probably your are using maven resource filtering: in this case, as detailed in this post, the keys of the property value to filter and it’s respective Spring property-placeholder cannot be the same.
Related
I am new to Spring Framework.I am trying to merge two sets using spring.
Beans.xml
<bean name = "mainAccount" class="java.util.HashSet">
<constructor-arg>
<set>
<value>123</value>
<value>1234</value>
</set>
</constructor-arg>
</bean>
<bean name = "subAccount" class="java.util.HashSet" parent="mainAccount">
<constructor-arg>
<set merge="true">
<value>231</value>
<value>23221</value>
</set>
</constructor-arg>
</bean>
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<constructor-arg name="AccountIDs" ref="subAccount" />
</bean>
I am not able to merge the sets in to the subAccount set.
I am getting the exception :-
Related cause:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'subAccount' defined in class path resource [Beans.xml]: Unsatisfied dependency expressed through constructor argument with index 0 of type [int]: Could not convert constructor argument value of type [java.util.LinkedHashSet] to required type [int]: Failed to convert value of type 'java.util.LinkedHashSet' to required type 'int'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.util.LinkedHashSet] to required type [int]: PropertyEditor [org.springframework.beans.propertyeditors.CustomNumberEditor] returned inappropriate value of type [java.util.LinkedHashSet]
My HelloWorld.java is :-
package com.tutorialspoint;
import java.util.HashSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
public class HelloWorld {
private final Set<String>AccountIDs;
public HelloWorld(Collection<String> AccountIDs){
this.AccountIDs = new HashSet<String>(AccountIDs);
Iterator iterator = AccountIDs.iterator();
while (iterator.hasNext())
System.out.print( iterator.next() + ", " );
System.out.println();
}
}
When I pass parent bean set "mainAccount" then it is showing the set values properly but when I try to pass the child bean "subAccount" I got the error.I want to merge the mainAccount to subAcount.I tried all posssible ways but not able to solve this.Some guidance would be helpful.
The issue here that i see is, the way you are trying to merge the collection. You are creating a instance of a collection and hoping that the merging will occur during construction of the Set.
How spring merging works is, you will have to define your own bean (Parent) with a property of collection say Set with property name say mySet, and then you can define your child bean with the same property name and declare the set's merge attribute to true. Thats when spring will understand which collection to merge with what.
You can follow below URL to see how its done
Collection Merging
Updated Beans.Xml. I have to add index.
<bean name = "mainAccount" class="java.util.HashSet">
<constructor-arg index="0">
<set>
<value>123</value>
<value>1234</value>
</set>
</constructor-arg>
</bean>
<bean name = "subAccount" class="java.util.HashSet" parent="mainAccount">
<constructor-arg index="0">
<set merge="true">
<value>231</value>
<value>23221</value>
</set>
</constructor-arg>
</bean>
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<constructor-arg name="AccountIDs" ref="subAccount" />
</bean>
I'm trying to create a MarshallingMessageConverter, here is my XML:
<bean id="marshallingMessageConverter" class="org.springframework.jms.support.converter.MarshallingMessageConverter">
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="marshaller" />
<property name="marshalTo" value="MARSHAL_TO_TEXT_MESSAGE" />
</bean>
I am getting the following error:
Error setting property values; nested exception is
org.springframework.beans.NotWritablePropertyException:
Invalid property 'marshalTo' of bean class
[org.springframework.jms.support.converter.MarshallingMessageConverter]:
Bean property 'marshalTo' is not writable or has an invalid setter method.
Does the parameter type of the setter match the return type of the getter?
Is this because MarshallingMessageConverter doesn't have a getMarshalTo method, and so setting it in this way isn't working?
It looks like it should be possible, as I found https://jira.spring.io/browse/SWS-614, and someone else said they have the following config working:
<bean id="marshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"/>
<bean id="xstream" class="org.springframework.oxm.support.MarshallingMessageConverter"
p:marshaller-ref="marshaller" p:unmarshaller-ref="marshaller" p:marshalTo="2"/>
<!--marshalTo=2 sets the marshaller to text message rather than bytes message-->
So I feel like maybe it's something I'm missing. I've tried using an int in the value, but that doesn't work either.
I want to use XML config because I'm using Spring Integration, and don't want to be pulling beans out of the app-context using Java.
I am using Spring version 3.2.1.RELEASE.
I was missing something... I was looking at the documentation for
org.springframework.oxm.support.MarshallingMessageConverter
but the one that I was using was
org.springframework.jms.support.converter.MarshallingMessageConverter
which has the method, toTargetType().
Not sure if I should delete my question or leave it here in case someone else does the same thing.
<context:property-placeholder
location="a.properties,b.properties"
ignore-unresolvable="true"/>
result: both properties file are loaded
<context:property-placeholder
location="${properties_location}"
ignore-unresolvable="true"/>
where properties_location is "a.properties,b.properties"
result: Exception in thread "main" org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [a.properties,b.properties] cannot be opened because it does not exist
edit: ${properties_location} is set the following way:
System.getProperties().setProperty("properties_location", "a.properties,b.properties");
ApplicationContext ctx = new GenericXmlApplicationContext("context.xml");
...
How can I initialize my application the 2nd way? to have all the properties file's path defined in a placeholder.
You have to change this to:
<context:property-placeholder
location="classpath:a.properties,
classpath:b.properties"
ignore-unresolvable="true"/>
From the source of the parser for the property-placeholder element.
String location = element.getAttribute("location");
if (StringUtils.hasLength(location)) {
String[] locations = StringUtils.commaDelimitedListToStringArray(location);
builder.addPropertyValue("locations", locations);
}
First the location is retrieved, if that has a value it is converted to a String[]. Springs conversion service takes care of replacing any placeholders in the String[]. But at that moment the properties_location placeholder is just a single element in the array and that gets resolved to a.properties,b.properties without further processing.
So at the moment this isn't possible with placeholders I'm afraid.
One thing that might work is using SpEL if it is always going to be a system property you can use #{systemProperties['properties_location']} to resolve the value. That should be resolved before anything else.
You cant use a property placeholder as a value in a placeholder placeholder resolver. Its like saying, "hey, resolve the placeholder for the location of the all the properties, and then you can start resolving properties!".
Logically it just dosent make sense. I was experimenting with spring property placeholder resolution recently, and stumbled upon this same question. I attempted to use two property placeholder configurers, one to resolve the location of the properties for the second, and the second to resolve the rest of the properties. Of course this dosent work due to the way in which spring initialises its beans.
Initialise bean post processors
Construct them
Construct all other beans
Since the property placeholder configurer is a bean post processor, if you have more than one of them, they get initialised and constructed at the same time, so know nothing of each others properties at construction
Edit
Given that the property location is a system property you could have:
System.getProperties().setProperty("properties_location_a", "classpath:/a.properties");
System.getProperties().setProperty("properties_location_b", "classpath:/b.properties");
And then in your spring content.xml:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>${properties_location_a}</value>
<value>${properties_location_b}</value>
</list>
</property>
</bean>
I have a problem with the followingspring context configuration file:
...
<context:property-override location="classpath:query_1.properties" />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:query_2.properties" />
</bean>
....
The problem is that the properties in the file "query_2.properties" cannot be found. The exception I get ist he following one:
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException. Could not resolve placeholder...
Now my question: is it possible that the combination of context:property-override and PropertyPlaceholderConfigurer does make no sense? Can anyone explain me in simple words what is the difference between both? Any help would be appreciated.
Thx. Horace
Property placeholders, normally defined using a <context:property-placeholder location=../> resolves the placeholders in bean definitions:
for eg.
<bean name="myclass" class="MyClass">
<property name="prop1" value="${prop1val}/>
</bean>
if the location specified with property placeholder has a property with name prop1val:
prop1val=aval
then it will be replaced in the bean myclass.
PrpertyOverrideConfigurer defined using <context:property-override location="classpath:query_1.properties" /> on the other is like a push mechanism, the property is of the form beanname.property and it would push this property into the bean with name beanname.
For eg. for the above case if the location had a property of:
myclass.prop1=aval
then it would inject in prop1 of myclass bean
The exception you are getting simply indicates that it is not able to find query_2.properties file, I doubt if it is any other configuration issue.
On which one will take effect if both are defined, I think the last one will the one to take effect.
I am trying to write a ValidatorFactory which will give me a validator based on its type
public Validator getNewValidator(ValidatorType type){
switch:
case a : new Validator1();
break;
case b : new Validator2();
break;
}
I want to write using spring xml beans definition
I can use method injection but it will let me create only one object and the method does
not take any arguments.
I don't want to use FactoryBean.. I am just looking whether we can do this using spring xml
bean definition.
you can do conditional bean injection with plain xml. The "ref" attribute can be triggered by property values from a property file and thus create conditional beans depending on property values. This feature is not documented but it works perfect.
<bean id="validatorFactory" class="ValidatorFactory">
<property name="validator" ref="${validatorType}" />
</bean>
<bean id="validatorTypeOne" class="Validator1" lazy-init="true" />
<bean id="validatorTypeTwo" class="Validator2" lazy-init="true" />
And the content of the property file would be:
validatorType=validatorTypeOne
To use the property file in your xml just add this context to the top of your spring config
<context:property-placeholder location="classpath:app.properties" />
For complex cases (more complex than the one exposed), Spring JavaConfig could be your friend.
If you are using annotation (#Autowired, #Qualifier etc) instead of xml, you are not able to make conditional beans work (at least at current version 3). This is due to #Qualifier does not support expression
#Qualifier(value="${validatorType}")
More information is at https://stackoverflow.com/a/7813228/418439
I had an slightly different requirements. In my case I wanted to have encoded password in production but plain text in development. Also, I didn't have access to parent bean parentEncoder. This is how I managed to achieve that:
<bean id="plainTextPassword" class="org.springframework.security.authentication.encoding.PlaintextPasswordEncoder"/>
<bean id="shaPassword" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
<constructor-arg type="int" value="256"/>
</bean>
<bean id="parentEncoder" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg ref="${password.encoding}Password"/>
</bean>
</property>
</bean>
Of course, I defined password.encoding in a property file with possible values as sha or plainText.
You should be able to do this:
<bean id="myValidator" factory-bean="validatorFactory" factory-method="getNewValidator" scope="prototype">
<constructor-arg><ref bean="validatorType"/></constructor-arg>
</bean>
<bean id="validatorType" ... />
Of course, it uses an automatically configured FactoryBean underneath but you avoid any Spring dependency in your code.