Spring - List of bean references from properties files? - java

I have this:
<bean class="...">
<constructor-arg name="beans">
<list>
<ref bean="beanA" />
<ref bean="beanB" />
</list>
</constructor-arg>
</bean>
I want to configure the list via a properties file, something like:
Properties file:
beans=beanA,beanB
XML file:
<bean class="...">
<constructor-arg name="beans">
<list refs="${beans}" />
</constructor-arg>
</bean>
Is something like this possible with Spring?
Edit: Just to give some context in case there are alternative solutions to the problem, this is for an application that has to write to multiple databases, and I want to configure which databases are enabled in the properties file, so that I don't have to maintain separate XML files for dev/production.

My first though is to use a FactoryBean where you inject the property ${beans} and the application context. Then in the factory bean, you loop on on every bean id/name and you call the context to retrieve the bean by name/id. Then you constructs your bean with your constructor and the list you have just built.

use annotation i.e.
#Value("${beans}")
private Class<? extends YourBean>String[] beanList;

Related

Spring : Initialization of properties before any bean creation

I have the project structure as following -
Facade -> Service-> DAO
In the DAO layer, when the beans are initialized then many dependencies are injected from a property file. Therefore, the properties file must be read first and then the remaining dao beans must be created. When the application is started then it gives an error that Spring cannot resolve a placeholder.
The DAO-application-context.xml is like-
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="prop">
<value>app.properties</value>
</property>
</bean>
<import resource = "a-dao.xml" />
<import resource = "b-dao.xml" />
<import resource = "c-dao.xml" />
Now in all the child application contexts i.e. a-dao, etc, we have-
<bean ....>
<property name = "xyz">
<value>${appValue}<value/>
</property>
<bean>
The error received is that appValue cannot be resolved. I think that it may be due to incorrect sequence of bean creation. However, the same config is working in another larger project.
I have checked Order of Spring Bean Initialization but implementing that solution would not be feasible. Is there any other way ?
Reg this Block of Configuration, property prop seems to be wrong
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="prop">
<value>app.properties</value>
</property>
</bean>
According to the Spring documentation
You could use the property location or locations to set the one or multiple values of the properties file.
So the code should be refactored to
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>app.properties</value>
</property>
</bean>

Spring Boot: Properties in Parent/Child Context

So, Spring Boot automatically loads the application.properties and makes the properties available for it´s ApplicationContext, so that i.e. XML-Bean-Definitions can use them.
But i can´t find a way to "expose" these properties to Child-Contexts. I have to define a Bean for a PropertyPlaceholder in each Childcontext to manually load the application.properties from the classpath.
Is there a way to give the properties to the ChildContext, so that they are automatically resolved when used? I don´t want to load the .properties-File in the Child-Context.
Basically i create the parent-Child-Relationship with
new SpringApplicationBuilder(Application.class).child(BaseApplication.class).run();
If i have a application.properties (defined in the Application-Module) with a property called username=XXX, i can access this property of course inside the Application-Module.
But, if i have a Beandefinition inside the Child-Context (BaseApplication), let´s say:
<bean id="beanB" class="com.example.nsm.BeanB" >
<constructor-arg index="0" value="${username}"/>
<constructor-arg index="1" value="${password}"/>
</bean>
the properties are not resolved. I have to manually load the application.properties from the classpath with
<bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
Then they are resolved.
In fact, i do not want to load the properties like this.
Beandefinitions from parent are visible for the Child, but properties are not? Why not? Is this intentional? If not, can this be fixed?

Referring a component bean in XML - Spring

I have a bean A that's annotated as Component. I am creating a map in Spring Config XML with the bean A as one of the values in the map. Is there anyway i can avoid creating the bean A in the config xml and just refer as it is annotated as Component.
Thanks.
All annotated components will be available with the same class name (camelCase) by default. I think you can use that name in the XML file.
<property name="taskList">
<list>
<ref bean="componetClass1" />
<ref bean="componetClass2" />
<ref bean="componetClass3" />
<ref bean="componetClass4" />
</list>
</property>
In this case ComponentClass1 etc are the class names which are annotated with #Component annotation.

constructor-arg and property together in bean definition

<bean id="cObject" scope="request" class="x.y.z.CClass"/>
<bean id="bObject" scope="request" class="x.y.z.BClass"/>
<bean id="aObject" scope="request" class="x.y.z.AClass">
<constructor-arg ref="bObject" />
<property name="cRef" ref="cObject" />
</bean>
aObject.cRef is not getting set for some reason. Note that constructor-arg and property are used in the same definition. I have not seen an example / post with similar feature.
On same sources my colleague discover:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'service.MenuService#0'
defined in class path resource [spring-beans/integrator.xml]:
Could not resolve matching constructor (hint: specify index/type/name
arguments for simple parameters to avoid type ambiguities)
while my host, test and production servers have no such error.
With:
<bean class="service.MenuService">
<constructor-arg index="0" type="java.lang.String" value="#{user}"/>
<constructor-arg index="1" type="java.lang.String" value="#{password}"/>
<constructor-arg index="2" type="java.lang.String" value="#{uri}"/>
<property name="system" value="OPRT"/>
<property name="client" value="OPRT"/>
</bean>
while there are only one 3-args constructor in bean.
The reason to use constructor - it perform some additional actions on non-Spring library by invoking init() method. And set args as fields.
So I change spring-beans.xml to:
<bean class="service.MenuService" init-method="init">
<property name="login" value="#{user}"/>
<property name="password" value="#{password}"/>
<property name="httpsUrl" value="#{uri}"/>
<property name="system" value="OPRT" />
<property name="client" value="OPRT" />
</bean>
Take attention to init-method= part.
UPDATE After all I wrote simple XML config and step through Spring source code in debugger. Seems that with Spring 3.x it's possible to combine constructor-arg and property in XML bean definition (check doCreateBean in AbstractAutowireCapableBeanFactory.java, which call createBeanInstance and populateBean next).
See also https://softwareengineering.stackexchange.com/questions/149378/both-constructor-and-setter-injection-together-in-spring/
Mixing <constructor-arg> and <property> is generally a bad idea.
There is only one good reason for using <constructor-arg>, and that is to create immutable objects.
However, your objects are not immutable if you can set their properties. Don't use <constructor-arg>. Redesign the class, use an initializer method annotated with #PostConstruct if you need to apply some logic at bean creation time.

spring: a bean that receives a list of Classes

I want to define in my Spring XML context a bean that has a property of the type List of classes: i.e. List<Class<?>> classes
How do I send that bean a number of classes, say java.lang.String and java.lang.Integer?
The list needs not be reusable, i.e. I will not refer to it in another bean.
With Spring, the simplest possibility usually works.....
<property name="classes">
<list>
<value>java.lang.String</value>
<value>java.lang.Integer</value>
</list>
</property>
<property name="classes">
<list>
<bean class="java.lang.Class" factory-method="forName">
<constructor-arg value="java.lang.String"/>
</bean>
</list>
</property>
Something like that...

Categories