I'd like to create a number of beans from a single class, all to be instantiated in the current application context, each based on prefixed properties in a properties file. I've given an example of what I'm trying to achieve. Any tips on how to do this without excessive code (e.g. without multiple classes, complicated factories, etc.) would be appreciated.
XML configuration:
<bean id="bean1" class="Mybean">
<property name="prefix" value="bean1"/>
</bean>
<bean id="bean2" class="Mybean">
<property name="prefix" value="bean2"/>
</bean>
<bean id="bean3" class="Mybean">
<property name="prefix" value="bean3"/>
</bean>
Properties File:
bean1.name=alfred
bean2.name=bobby
bean3.name=charlie
Class:
class Mybean {
#Value("${#{prefix}.name}")
String name;
}
Main Class:
public class Main {
#Autowired
List<MyBean> mybeans;
}
You can use PropertyPlaceholderConfigurer to set bean's name directly (instead of storing its prefix):
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="app.properties"/>
</bean>
<bean id="bean1" class="Mybean">
<property name="name" value="${bean1.name}"/>
</bean>
<bean id="bean2" class="Mybean">
<property name="name" value="${bean2.name}"/>
</bean>
<bean id="bean3" class="Mybean">
<property name="name" value="${bean3.name}"/>
</bean>
Related
I have this kind of class:
Class Food
int type
String name
Class Dog
String dogName
Food food
I want to Init the Dog class using Spring properties, I have no problem to init the dogName value by doing this:
<bean id="dog" class="....Dog">
<property name="dogName" value="dog"/>
...
</bean>
How to set a value for the Food Object?
Use the ref in to refer to the bean id of the food.
<bean id="food" class="....Food"></bean>
<bean id="dog" class="....Dog">
<property name="dogName" value="dog"/>
<property name="food" ref="food"/>
</bean>
<bean id="dog" class="c...dog">
<property name="dogName" value="dog"/>
<property name="food" >
<bean class="...food">
<property name="type" value="1"/>
<property name="name" value="chicken"/>
</bean>
</property>
</bean>
and in case of inner but you can't use it outside of the parent bean tag
<bean id="dog" class="c...dog">
<property name="dogName" value="dog"/>
<property name="food" >
<bean class="...food">
<property name="type" value="1"/>
<property name="name" value="chicken"/>
</bean>
</property>
</bean>
<property name="food">
<bean class="...Food">
<property name="type" value="1"/>
<property name="name" value="Apple"/>
</bean>
</property>
See Spring 3.3.2.3. Inner beans:
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.
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
Use the ref in <property> to refer to the bean id of the food.
<bean id="food" class="....Food">
</bean>
<bean id="dog" class="....Dog">
<property name="dogName" value="dog"/>
<property name="food" ref="food"/>
</bean>
I'm trying to integrate Mybatis with spring. Here you can see my application context of Spring
<context:annotation-config />
<context:component-scan base-package="com" />
<tx:annotation-driven />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/DB" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:/com/mybatis/mybatis-config.xml" />
<!--<property name="transactionFactory" ref="springManagedTransactionFactory" />-->
</bean>
<!--
<bean id="springManagedTransactionFactory" class="org.mybatis.spring.transaction.SpringManagedTransactionFactory">
<constructor-arg index="0" ref="dataSource" />
</bean> -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="registroClimaMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.mybatis.dao.RegistroClimaMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
First of all I have commented springManagedTransactionFactory in XML because it's giving me an exception
Error creating bean with name 'springManagedTransactionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
Here is my interface RegistroClimaMapper. I do not have any annotation here because I have defined the context:component scan.
public interface RegistroClimaMapper {
void insertarRegistroClima(RegistroClima registro) throws SQLException;
List<RegistroClima> getRegistrosClima() throws SQLException;
List<RegistroClima> getRegistrosClima(#Param("Validado") boolean Validado) throws SQLException;
}
I try to use this interface in a ManagedBean and when I'm going to use registroClimaPersistence inside a method of TablaRegistroClimaBean I get a NullPointerException
#ManagedBean(name = "tablaRegClimaBean")
#ViewScoped
public class TablaRegistroClimaBean implements Serializable {
#Autowired
private RegistroClimaMapper registroClimaPersistence;
public void setRegistroClimaPersistence(RegistroClimaMapper registroClimaPersistence) {
this.registroClimaPersistence = registroClimaPersistence;
}
}
As seen here: http://javadox.com/org.mybatis/mybatis-spring/1.1.1/org/mybatis/spring/transaction/SpringManagedTransactionFactory.html#SpringManagedTransactionFactory%28%29, SpringManagedTransactionFactory has a default constructor, but none that takes a datasource. You need to pass the datasource to the newTransaction() method, but not to the constructor: http://javadox.com/org.mybatis/mybatis-spring/1.1.1/org/mybatis/spring/transaction/SpringManagedTransactionFactory.html#newTransaction(javax.sql.DataSource,%20org.apache.ibatis.session.TransactionIsolationLevel,%20boolean)
Change the piece of code to
<bean id="springManagedTransactionFactory" class="org.mybatis.spring.transaction.SpringManagedTransactionFactory">
<!--<constructor-arg index="0" ref="dataSource" />-->
</bean>
or completely remove the constructor-arg.
What NullPointerException do you get? It might come from you just defining the RegistroClimaMapper interface, but not implementing this interface in any bean. Please add a Bean that implements this interface and the Autowired annotation should work.
I need 3 beans, each with 3 properties 2 of them are related properties values from anothers beans but they differ in only 1 property. I have something like this:
<bean id="a" class="myClassPath" scope="prototype">
<property name='status' value='#{otherBean.myMethod()}'/>
<property name='code' value='#{otherBean.myOtherMethod()}'/>
<property name='typeOf' value='1'/>
</bean>
<bean id="b" class="myClassPath" scope="prototype">
<property name='status' value='#{otherBean.myMethod()}'/>
<property name='code' value='#{otherBean.myOtherMethod()}'/>
<property name='typeOf' value='2'/>
</bean>
<bean id="c" class="myClassPath" scope="prototype">
<property name='status' value='#{otherBean.myMethod()}'/>
<property name='code' value='#{otherBean.myOtherMethod()}'/>
<property name='typeOf' value='3'/>
</bean>
This code is very redundant. Can I if like define a bean and some kind override only the property typeOf?
UPDATE
the value of status and code are defined in others beans using Spring language this is in some way a example.
Take advantage of the bean template inheritance for a scenario like this:
<bean id="yourCommonProperties" abstract="true" scope="prototype">
<property name="status" value='#{otherBean.myMethod()}'/>
<property name="code" value='#{otherBean.myOtherMethod()}'/>
</bean>
Here we are not specifying the class but just sharing the common properties and refer this using parent attribute in each of the bean definition as:
<bean id="a" class="myClassPath" parent="yourCommonProperties" scope="prototype">
<property name='typeOf' value='1'/>
</bean>
<bean id="b" class="myClassPath" parent="yourCommonProperties" scope="prototype">
<property name='typeOf' value='2'/>
</bean>
<bean id="c" class="myClassPath" parent="yourCommonProperties" scope="prototype">
<property name='typeOf' value='3'/>
</bean>
Yup, just in your class definition do as follows:
...
private boolean status = true;
private int code = 13;
private int typeOf;
...
and then Spring config would be like:
<bean id="a" class="myClassPath" scope="prototype">
<property name='typeOf' value='1'/>
</bean>
For example use autowired="byName", and create beans with status and code names:
<bean id="status" class="java.lang.Boolean">
<constructor-arg value="true"/>
</bean>
<bean id="code" class="java.lang.Integer">
<constructor-arg value="13"/>
</bean>
<bean id="a" class="myClassPath" autowired="byName" scope="prototype">
<property name='typeOf' value='1'/>
</bean>
<bean id="b" class="myClassPath" autowired="byName" scope="prototype">
<property name='typeOf' value='2'/>
</bean>
<bean id="c" class="myClassPath" autowired="byName" scope="prototype">
<property name='typeOf' value='3'/>
</bean>
I have a class called let's say A with such a setter:
//class A
#Inject
public void setAProvider(Provider<B> b)
{
this.b = b;
}
It works fine with javax.inject and annotation configuration when I want to have only one kind of A instance..
My problem is that I want to have two instances of class A, one with Provider<B1> and second with Provider<B2>. My question is how to express my requirements in Spring xml configuration?
Actually, it is briefly answered here, you need ProviderCreatingFactoryBean .
This is an example :
<bean id="a" class="a.b.b.A" scope="prototype">
<property name="xxx" value="15000"/>
</bean>
<bean id="b" class="a.b.b.B" scope="prototype">
<property name="zzz" value="-1"/>
</bean>
<bean id="providerOfA" class="org.springframework.beans.factory.config.ProviderCreatingFactoryBean">
<property name="targetBeanName" value="a"/>
</bean>
<bean id="providerOfB" class="org.springframework.beans.factory.config.ProviderCreatingFactoryBean">
<property name="targetBeanName" value="b"/>
</bean>
<bean id="barServiceA" class="a.b.c.BarService">
<property name="provider" ref="providerOfA"/>
</bean>
<bean id="barServiceB" class="a.b.c.BarService">
<property name="provider" ref="providerOfB"/>
</bean>
I have several Spring beans in which one of the property value for all of them are same String value. Is there a way where I can define this String in XML at one place and refer it in all beans at property value settings?
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="someValue"></property>
<property name="commonProperty" value="commonValue"></property>
<bean id="nextBean" class="test.NextBean">
<property name="property2" ref="someValue"></property>
<property name="commonProperty" value="commonValue"></property>
How to set commonValue in a seperate place and refer it in both places?
Try like this.
<bean id="commonConfig" abstract="true">
<property name="commonField" value="CommonValue"></property>
</bean>
<bean id="class1" class="com.dataclass.Class1" parent="commonConfig">
<property name="field1" value="value1"></property>
</bean>
<bean id="class2" class="com.dataclass.Class2" parent="commonConfig">
<property name="field2" value="value2"></property>
</bean>
Class1 & Class2 having one common field name "commonField", parent attribute is use for this common purpose only.
In Spring this is called bean definition inheritance(this is not java class inheritance, above example Class1 & n Class not inheriting in their respective java file.)
For more detail, look at Spring doc's link.
I've never tried it before, but this should work
<bean id="commonProp" class="java.lang.String">
<constructor-arg name="original" value="yourString"></constructor-arg>
</bean>
Then, in every bean you need to reference it:
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="someValue"></property>
<property name="commonProperty" ref="commonProp"></property>
</bean>
You can define your string properties in some "init_constants.properties" file. Then you should load properties file in spring xml:
<bean id="properties"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:db.properties</value>
<value>classpath:mail.properties</value>
<value>classpath:init_constants.properties</value>
</list>
</property>
</bean>
And after that you can inject this properties using xml:
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="{$prop1}"></property>
<property name="commonProperty" value="commonValue"></property>
</bean>
or in code using #Value annotation:
#Value(value="${prop1}")
private String property1;
Well If commonValue is string then you can put it in properties file and read it using #Value annotation.