Spring - Inject bean from a factory class - java

I have the following in my class:
public class Manager {
private Apple apple = AppleFactory.createInstance();
// .....
}
appContext.xml:
<bean id="manager" class="Manager"/>
AppleFactory is an external library on which I do not have any control over. I use xml configuration(appContext.xml) for wiring the beans. How can I inject the field apple from appContext.xml?

<bean id="apple" class="AppleFactory" factory-method="createInstance" />
<bean id="manager" class="Manager"/>
<context:annotation-config />
Your manager
public class Manager {
#Autowired
private Apple apple;
}
Should do the trick.
See the reference guide and Initializing Spring bean from static method from another Class?

You can use following configuration :
<bean id="apple" class="jarpackagename.AppleFactory"
factory-method="createInstance">
</bean>
<bean id="manager" class="pkgname.Manager">
<property name="apple" ref="apple">
</bean>

You can configure Manager bean as follows
<bean class="xxx.Manager">
<property name="apple">
<bean class="yyy.AppleFactory" factory-method="createInstance" />
</property>
</bean>

Related

Spring dependency injection not working

I've got a problem in my standalone Java application. The thing is that I'm trying to Autowire both my Services and my DAOs, but I get a NullPointerException when I invoke service methods from the UI since dependency injection is not working properly. I've tried a lot of things, many of them from similar questions, but the problem is still there. I'm using Spring 4.0.6.RELEASE and Hibernate 4.3.11.Final. Here is my code:
1 - Invocation of service:
public class LoginView {
#Autowired
private UsuarioService usuarioService;
...
...
JButton btnAutenticarse = new JButton("Autenticar");
btnAutenticarse.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Usuario usuario = usuarioService.login(textField.getText(),
String.valueOf(passwordField.getPassword()), false); // NullPointerException
} catch (InstanceNotFoundException e1) {
...
2 - Definition of service:
#Service("usuarioService")
public class UsuarioServiceImpl implements UsuarioService {
#Autowired
private UsuarioDao usuarioDao;
...
3 - Definition of DAO:
#Repository("usuarioDao")
public class UsuarioDaoHibernate extends GenericDaoHibernate <Usuario, Long>
implements UsuarioDao {
...
4 - Definition of GenericDAO:
public class GenericDaoHibernate<E, PK extends Serializable> implements
GenericDao<E, PK> {
#Autowired
private SessionFactory sessionFactory;
....
5 - AppConfig.java:
#Configuration
#ComponentScan(basePackages = "org.example.model")
public class AppConfig {
#Bean(name = "usuarioService")
public UsuarioService usuarioService() {
return new UsuarioServiceImpl();
}
#Bean(name = "usuarioDao")
public UsuarioDao usuarioDao() {
return new UsuarioDaoHibernate();
}
6 - spring-config.xml:
<!-- Enable usage of #Autowired. -->
<context:annotation-config/>
<!-- Enable component scanning for defining beans with annotations. -->
<context:component-scan base-package="org.example.model"/>
<!-- For translating native persistence exceptions to Spring's
DataAccessException hierarchy. -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<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/appdb" />
<property name="username" value="username" />
<property name="password" value="password"/>
</bean>
<bean id="dataSourceProxy" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"
p:targetDataSource-ref="dataSource"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>org.example.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<!-- Enable the configuration of transactional behavior based on
annotations. -->
<tx:annotation-driven transaction-manager="transactionManager" />
Spring will only inject Autowired fields in Spring managed beans. AKA if you are using new LoginView() Spring cannot inject dependencies.
public class LoginView {
#Autowired
private UsuarioService usuarioService;
}
should be
#Component
public class LoginView {
#Autowired
private UsuarioService usuarioService;
}
If you can't let Spring manage that class, you'll need to design it a different way.
I'd recommend you use constructor injection instead of field injection, by the way.
What I might do is make another class to be a Spring managed bean and do something like this:
#Component
public class InitClass{
private UsarioService usarioService;
#Autowired
public InitClass(UsarioService usarioService){
this.usarioService = usarioService;
}
#PostConstruct
public void init(){
new LoginView(usarioService);
}
}
Then this class will handle all the initialization you're doing now in #PostConstruct. It may be required to do this in #PostConstruct as Spring beans may not be fully initialized until then.
However, without seeing how everything is initialized, it's hard to tell what the best strategy would be.
Make explicit component scan in the application context file. I did like this and it worked for me.
<context:component-scan base-package="com.example" />
You can see more information in the link here

Spring's nested transactions with different transactionManagers

I'm new to Spring's transaction management having troubles to tackle the following scenario of nested transactions while integrating Spring (3.2) and Hibernate (3.6).
I've declared two appContext files as following.
File1) applicationContext-student.xml
<bean id="studentProjSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
...**dataSource1_on_Machine1**...
</bean>
<bean id="studentProjTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="studentProjSessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="studentProjTransactionManager" />
<bean id="studentDao" class="com.my.univ.employee.dao.studentHibDao" scope="singleton" />
<bean id="studentService" class="com.my.univ.student.service.studentServiceImpl" scope="singleton">
<property name="studentDao" ref="studentDao" />
</bean>
File2) applicationContext-employee.xml
<bean id="employeeProjSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
........**dataSource2_on_Machine2**...
</bean>
<bean id="employeeProjTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="employeeProjSessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="employeeProjTransactionManager" />
<bean id="employeeDao" class="com.my.univ.employee.dao.EmployeeHibDao" scope="singleton" />
<bean id="employeeService" class="com.my.univ.employee.service.EmployeeServiceImpl" scope="singleton">
<property name="employeeDao" ref="employeeDao" />
</bean>
Imported above two files in the following file.
File3) applicationContext-university.xml
<import resource="applicationContext-student.xml" />
<import resource="applicationContext-employee.xml" />
<bean id="personService" class="com.my.univ.person.service.PersonServiceImpl" scope="singleton">
<property name="studentService" ref="studentService" />
<property name="employeeService" ref="employeeService" />
</bean>
Questions
Let's assume that method level #Transactional annotations are provided with the right txManager names in studentService and employeeService but not in personService.
Q1) If I declare a method in personService as #Transactional, which txManager gets picked?
Q2) How does the nested txManager scenario work if the txManagers in the hierarchy are different from each other?
Ex: If a #Transactional method in personService invokes a #Transactional method in studentService and then another #Transactional method in employeeService (with in the same method of personService).
Q3) How does the commit, rollback elements work in above scenario.
Q4) Readonly operations vs Read/Write operations in above scenario.
It'd be great if anybody could clarify the above.
Thanks.
The #Transactional annotation takes as a value the bean name of the transaction manager. From the documentation:
public abstract String value
A qualifier value for the specified transaction.
May be used to determine the target transaction manager, matching the qualifier value (or the bean name) of a specific PlatformTransactionManager bean definition.
Default:
""
So in your case, explicitly defining:
#Transactional("studentProjTransactionManager")
#Transactional("employeeProjTransactionManager")
should wrap transactionally using the right transaction manager.

Compound beans in Spring?

Suppose I have my own bean which contains another beans hardcoded.
How to join this with Spring configuration?
First way is to use factory-method:
<bean id="bean1" class="myClass1"/>
<bean id="bean1.member" factory-bean="bean1" factory-method="getMember"/>
<bean id="bean2" class="myClass2">
<property name="collaborator" ref="bean1.member"/>
</bean>
Another way is to use EL:
<bean id="bean1" class="myClass1"/>
<bean id="bean2" class="myClass2">
<property name="collaborator" value="#{bean1.member}"/>
</bean>
In latter case Spring does not realize the dependency. Anyway, Bean Graph in Eclipse displays beans unrelated.
Are there better ways? May be I may implement some interface with MyClass1 so that it will treated as container or context?
You should create a separate bean for bean1.member and inject it into bean1
<bean id="bean3previouslyMember" class="myCompoundBean"/>
<bean id="bean1" class="myClass1">
<property name="member" ref="bean3previouslyMember"/>
</bean>
<bean id="bean2" class="myClass2">
<property name="collaborator" ref="bean3previouslyMember"/>
</bean>
Unless myClass1 is not modifiable and has no setter, this is generally what we do.

Running <jdbc:initialize-database> at the beginning of context creation

I need to execute SQL script before PropertyPlaceholderConfigurer is initialized in Spring's context, as soon as application properties are stored in the database and this script should insert them. But currently placeholder is initialized earlier, which leads to errors.
Is there a way to execute <jdbc:initialize-database data-source="dataSource" ... before <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" ... in Spring?
Or is there a way to initialize placeholderConfig bean later? I tried to use depends-on, lazy-init attributes for this bean, but it didn't help. Thanks in advance.
Another solution without creating any Bean:
If you've got one <jdbc:initialize-database /> you can add this property depends-on="org.springframework.jdbc.datasource.init.DataSourceInitializer#0" to your bean <bean id="placeholderConfig" />
If you have more than one <jdbc:initialize-database /> adapt the #0.
Here is how I solved that. I created a class Initializer. This class in its constructor executes plain old sql statements (java.sql.Statement), creates table (if it doesn't exist), and inserts properties (if they are not there). The dataSource bean is passed in the context to this constructor, and placeholderConfig bean uses depends-on="initializerBean". So, properties appear in the database before they are used.
This script
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc">
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath:database/drop_schema.sql" />
<jdbc:script location="classpath:database/create_schema.sql" />
<jdbc:script location="classpath:database/sample_data.sql"/>
</jdbc:initialize-database>
<!-- Other bean definitions -->
</bean>
is essentially a shortcut to
<bean class="org.springframework.jdbc.datasource.init.DataSourceInitializer" id="dataSourceInitializer">
<property name="databasePopulator" ref="resourceDatabasePopulator"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="resourceDatabasePopulator"
class="org.springframework.jdbc.datasource.init.ResourceDatabasePopulator">
<property name="scripts">
<array>
<value>classpath:database/drop_schema.sql</value>
<value>classpath:database/create_schema.sql</value>
<value>classpath:database/sample_data.sql</value>
</array>
</property>
</bean>
Note that I've added id to the DataSourceInitializer bean. Now you can reference it in PropertyPlaceholderConfigurer's depends-on attribute. That way you declare that your PropertyPlaceholderConfigurer should be created after DataSourceInitializer.
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" depends-on="dataSourceInitializer"/>
In my case db was initialized after the LocalContainerEntityManagerFactoryBean had been created and Hibernate was unable to validate my schema.
The documentation explains how to deal with these problems:
http://static.springsource.org/spring/docs/3.0.0.RC3/reference/html/ch12s09.html
12.9.1.1 Initialization of Other Components that Depend on the Database
Our use case was arguably even more complex. We're using flyway for database migrations and it needs to be started before the entityManagerFactory is created. The problem for us was that <jdbc:initialize-database /> was only used in our migration tests and thus initialized in a different application context than flyway and the entityManagerFactory. So we couldn't simply use L. BIZE answer and let our flyway bean depend on org.springframework.jdbc.datasource.init.DataSourceInitializer#0 because it might not exist (i.e. in production it doesn't exist). We ended up creating a custom factory bean like this:
class OptionalBeanInitializer extends AbstractFactoryBean implements BeanFactoryAware {
private String beanName;
private BeanFactory beanFactory;
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
#Override
public Class<?> getObjectType() {
return OptionalBeanInitializer.class;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
#Override
protected Object createInstance() throws Exception {
if (beanFactory.containsBean(beanName)) {
// Initialize
beanFactory.getBean(beanName);
}
return new OptionalBeanInitializer();
}
}
Which we could use to depend on our optional dependency like this:
<bean id="optionalDataSourceInitializer" class="com.x.y.z.OptionalBeanInitializer">
<property name="beanName" value="org.springframework.jdbc.datasource.init.DataSourceInitializer#0"/>
</bean>
<bean id="flyway" class="com.googlecode.flyway.core.Flyway" init-method="migrate" depends-on="optionalDataSourceInitializer">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory"
depends-on="flyway, optionalDataSourceInitializer">
<property name="dataSource" ref="dataSource"/>
</bean>
The OptionalBeanInitializer will take care of initializing the org.springframework.jdbc.datasource.init.DataSourceInitializer#0 bean only if it exists.
There are two simpler ways to add the depend-on attribute only for test context, and not for production context.
1/Override the bean in the test context.
In our case here is the production context :
<bean id="placeholderConfig" />
And the unit test context :
<bean id="placeholderConfig" depends-on="org.springframework.jdbc.datasource.init.DataSourceInitializer#0" />
Make sure that the unit test context is loaded before the production context and the good placeholderConfig bean will be instanciated, after the jdbc:initialize-database phase.
2/Another way is to use profiles
<beans profile="!test">
<bean id="placeholderConfig" .../>
</beans>
<beans profile="test">
<jdbc:initialize-database data-source="dataSource" .../>
<bean id="placeholderConfig" depends-on="org.springframework.jdbc.datasource.init.DataSourceInitializer#0" .../>
</beans>

spring: set property of one bean by reading the property of another bean?

Is it possible to set the property of one bean by reading the property of another bean? For instance, suppose I had:
class A {
void setList(List list);
}
class B {
List getList();
}
I would like Spring to instantiate both classes, and call A's setList method, passing in the result of calling B's getList method. The Spring configuration might look something like:
<bean id="b" class="B"/>
<bean id"a" class="A">
<property name="list" ref="b" ref-property="list"/>
</bean>
Alas, this made-up XML does not work.
Why not just inject B into A? Because I do not want to introduce the extra dependency. A is only dependent List, not on B.
in addition to #Kevin's answer if you are using spring 3.0 it is possible to do this with the new spring expression language
<bean id="a" class="A">
<property name="list"
value="#{b.list}"/>
</bean>
spring 3.0 documentation
There are a couple of ways. Here is one:
<bean id="b" class="B"/>
<bean id="a" class="A">
<property name="list">
<bean class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
<property name="targetObject" ref="b"/>
<property name="propertyPath" value="list"/>
</bean>
</property>
</bean>
Also see the <util:property-path/> element
If you are trying to do the same for a constructor then do this.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg type="javax.sql.DataSource" value="#{jdbc.dataSource}">
</constructor-arg>
</bean>
Here "jdbc" is as mentioned below that has property "dataSource" with getter and setter and initilized as:
<bean id="jdbc" class="com.la.activator.DataSourceProvider">
<property name="myDataSourcePool" ref="dsPoolService"/>
</bean>

Categories