Spring, XML beans call Annotation beans when app start - spring

I have one Annotation bean with some methods. It works fine.
public #Controller("adminController") class AdminController {
...
private #Autowired AdminDAO adminDAO;
public void resetTemporalList() {
System.out.println("HE SIDO EJECUTADO.");
this.adminDAO.resetTemporalRegisters();
}
...
}
Now, I am integrating one quartz task. But I am load it with XML definition beans that call previus annotation bean.
<bean id="resetTemporalRegisters" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="adminController" />
<property name="targetMethod" value="resetTemporalList" />
<property name="concurrent" value="false" />
</bean>
Whan I start my app appear next error.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'adminController' is defined
I believe the problem is that Spring load XML beans first, after Annotation beans, then in this moment "adminController" bean not exits...
How Can I fix it?
SOLVED IT!!
Problem was in I put xml bean definitions in applicationContext.xml.

No, XML and annotations integrate fine, but do you actually have the component scanning code in your XML?
<context:component-scan base-package="com.yourcompany.yourapp"/>
See: 4.10 Classpath scanning and managed components

A little bit of guessing: your controller is defined in child application context created by Spring MVC while you resetTemporalRegisters job in main application context (parent). Child context can access beans from parent context but not the other way around.
This raises important question: why is your business logic trying to call a method of a controller? These methods should be called only be the MVC framework. Can't you just call
this.adminDAO.resetTemporalRegisters();
directly from your job?
<bean id="resetTemporalRegisters" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="adminDAO" />
<property name="targetMethod" value="resetTemporalRegisters" />
<property name="concurrent" value="false" />
</bean>
adminDAO is probably defined in parent context, so you can access it easily.

Related

What to put into applicationContext and faces-config?

I created a JSF Application and I'm not sure what I should put into the faces-config?
One of my ManagedBeans looks like the following:
#ManagedBean(name = "ProfileBean")
#ViewScoped
public class ProfileBean implements Serializable
my applicationcontext
<context:annotation-config />
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean id="QuestionDao" class="code.elephant.dao.QuestionDao"></bean>
<bean id="QuestionService" class="code.elephant.service.QuestionService">
<constructor-arg ref="QuestionDao"/>
</bean>
<bean id="QuestionBean" class="controller.QuestionBean">
<constructor-arg ref="QuestionService"/>
</bean>
<bean id="UserDao" class="code.elephant.dao.UserDao"></bean>
<bean id="UserService" class="code.elephant.service.UserService">
<constructor-arg ref="UserDao"/>
</bean>
<bean id="LoginBean" class="controller.LoginBean">
<constructor-arg ref="UserService"/>
</bean>
<bean id="ProfileBean" class="controller.ProfileBean">
<constructor-arg ref="UserService" />
<property name="_LoginBean" ref="LoginBean"></property>
</bean>
my faces-config
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
I saw some examples which defines <managed-beans> in the java-faces.config but I already used the #ManagedBean annotation in the java class. Is this rly necessary? Is my setup up with jsf spring correct? Should I also define the managed beans in the faces-config?
The purpose of the SpringBeanFacesELResolver that you have configured in faces-config is to make it so that you can use Spring beans instead of the old-style JSF managed beans or CDI dependency injection.
Remove the #ManagedBean annotation from your ProfileBean class. You don't need it since you are using Spring instead of JSF's old managed beans mechanism.
The #ManagedBean annotation is a remnant from old versions of JSF; don't use it if you are using a newer version of JSF. Current versions of JSF use CDI (the standard Java EE API for dependency injection), but you are using Spring instead, so you should configure your beans the Spring way (which you are already doing since you've defined ProfileBean in your Spring XML config).

spring batch: inject main application context #Component using AutomaticJobRegistrar

I'm trying to inject some #Service / #Repository bean defined in main application context into some jobs loaded by AutomaticJobRegistrar.
<bean class="org.springframework.batch.core.configuration.support.AutomaticJobRegistrar">
<property name="applicationContextFactories">
<bean class="org.springframework.batch.core.configuration.support.ClasspathXmlApplicationContextsFactoryBean">
<property name="resources" value="classpath*:/META-INF/jobs/*Job.xml" />
</bean>
</property>
<property name="jobLoader">
<bean class="org.springframework.batch.core.configuration.support.DefaultJobLoader">
<property name="jobRegistry" ref="jobRegistry" />
</bean>
</property>
</bean>
Using #Autowired inside my ItemWriter implementation class do not inject my services beans.
I have to enable component scanning inside each *Job.xml or declare each bean in order to make injection works, but injected classes are not the same instance of that one used by main application context.
How can I get the same instance bean declared in main application context?
Thank you for any advice
Did you activate context:annotation-config for each job?
If a new applicationcontext is created for every Job you need to activate this or no annotationprocessing (including #Autowired) will happen.
'context:component-scan' also activates 'context:annotation-config' so this might be the reason #Autowired works if you activate it.

context:property-placeholder doesn't resolve references

I have next applicationContext.xml file on the root of classpath:
<context:annotation-config />
<context:property-placeholder location="classpath:props/datasource.properties" />
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource"
p:username="${jdbc.username}"
p:password="${jdbc.password}"
p:url="${jdbc.url}"
p:driverClassName="${jdbc.driverclass}"
p:validationQuery="SELECT sysdate FROM dual" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="datasource"
p:mapperLocations="classpath:mappers/*-mapper.xml" />
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="datasource" />
<bean id="mappeScannerConfigurere" class="org.mybatis.spring.mapper.MapperScannerConfigurer"
p:sqlSessionFactory-ref="sqlSessionFactory"
p:basePackage="com.mypackage" />
props/datasource.properties also exists on the root of classpath with such content:
jdbc.url=myjdbcurl
jdbc.driverclass=myClass
jdbc.username=myUserName
jdbc.password=myPassword
I have a spring managed test where I declare to use previously mentioned applicationContext.xml via next annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
When I invoke test method i get next error from spring:
org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class '${jdbc.driverclass}'
As I understand sping didn't resolve reference to jdbc.driverclass.
What have I done wrong?
PS: I'm using spring 3.2.3.RELEASE
**
EDIT
**
Perhaps the problem may be in MapperScannerConfigurer. It is a BeanDefinitionRegistryPostProcessor and as Javadoc says:
Extension to the standard BeanFactoryPostProcessor SPI,
allowing for the registration of further bean definitions
before regular BeanFactoryPostProcessor detection kicks in
So MapperScannerConfigurer instantiates datasource object via sqlSessionFactory with BeanFacoryPostProcessor(which is responsible for <context:property-placeholder/>) have not been utilized.
So my question transforms to how to reorder BeanFacoryPostProcessor from <context:property-placeholder/> and BeanDefinitionRegistryPostProcessor(MapperScannerConfigurer)?
Resolved
After a couple hours of investigation I found the solution:
As I said earlier MapperScannerConfigurer is a BeanDefinitionRegistryPostProcessor which fires before BeanFactoryPostProcessor which is responsible for <context:property-placeholder/>. So, during the creation of MapperScannerConfigurer references to external properties will not be resolved. In this case we have to defer the creation of datasource to the time after BeanFactoryPostProcessorhave been applied. We can do that in several ways:
remove p:sqlSessionFactory-ref="sqlSessionFactory" from MapperScannerConfigurer. In this case datasource object will not be created before MapperScannerConfigurer, but after BeanFactoryPostProcessor which is responsible for <context:property-placeholder/>. If you have more than one sqlSessionFactory in applicationContext, than can be some troubles
In versions of mybatis-spring module higher than 1.0.2 there is a possibility to set sqlSessionFactoryBeanName instead of sqlSessionFactory. It helps to resolve PropertyPlaceHolder issue with BeanFactoryPostProcessor. It is a recommended way to solve this issue described in mybatis-spring doc
I was having the same issue and came across this post but I was unable to resolve it the same way maks did. What ended up working for me was to set the ignoreUnresolvablePlaceholders property value to true.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:database.properties</value>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
I am using Spring 3.2.3.RELEASE as well. I realize this post is over 4 months old but I figured someone might find it useful.
Short form: What is the proper way to load an implementation of: BeanDefinitionRegistryPostProcessor?
Expanded form: Is there a way to load BeanDefinitionRegistryPostProcessor before any beans have been created. If you look at the javadoc:
Extension to the standard {#link BeanFactoryPostProcessor} SPI, allowing for
the registration of further bean definitions before regular
BeanFactoryPostProcessor detection kicks in.
So it's meant to be loaded when bean definitions have been created but before any beans have been created. If we just create it as a regular bean in the application xml then it defeats the purpose of having this bean in the first place.

Configuring Datasource in Spring 3.0

Hello guys I have configured a connection pool and JNDI resource in glassfish 2.1. I can get the Datasource via lookup method in my projects and everything works good. However I decided to try Spring framework and to use my existing connection pool.
In the Spring context file I have the following:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/name" />
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="dao" class="com.mycompany.mavenproject3.Dao">
<property name="simpleJdbcTemplate" ref="jdbcTemplate"/>
</bean>
When I deploy the project I get:
java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required]
Is there anything else I have to configure in that file or in any other file in order to get the Datasource?
Presumably, com.mycompany.mavenproject3.Dao extends JdbcDaoSupport, but you're setting a property named simpleJdbcTemplate on it, leading me to believe that you've defined your own property to hold the template since that doesn't exist on Spring's implementation. It's therefore complaining at you because you're required to set either the dataSource property or the jdbcTemplate property of the JdbcDaoSupport object before using it, exactly like it's telling you. Change <property name="simpleJdbcTemplate"... to <property name="jdbcTemplate"....
If your DAO doesn't extend JdbcDaoSupport, then find what does and remove it or set its properties appropriately.
You can also call your datasource directly in your dao bean, don't need to do an another bean for jdbcTemplate. So your context file become something like this:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/name" />
<bean id="dao" class="com.mycompany.mavenproject3.Dao">
<property name="dataSource" ref="dataSource"/>
</bean>
After you just have to extends JdbcDaoSupport spring class (in which contain the getter and setter of datasource) on your Dao class.

Spring MVC Application - How do I set a session scoped bean value

In my application I need to gather information on one screen and then display it on the next.
I have selected to store this information in a bean with a scope set as session ( it will be used in several other screens after the initial data gathering screen)
The Manager is configured as follows:
<bean name="/springapp.htm" class="foo.bar.controller.springcontroller">
<property name="sessionBeanManager" ref="sessionBeanManager" />
</bean>
The bean is configured as follows :
<bean id="sessionBean" class="foo.bar.sessionBean" scope="session">
<aop:scoped-proxy/>
<property name="beanValue" value="defaultValue" />
</bean>
<bean id="sessionBeanManager" class="foo.bar.sessionBeanManagerImpl">
<property name="sessionBean" ref="sessionBean"/>
</bean>
And I am outputting on the jsp page with
<c:out value="${sessionBean.beanValue}"></c:out>
but whenever I load the page the value is empty?
It seems to me that the bean is loading OK but is not populated with the value, which leads me to think that either the session bean is not being populated or the bean is not being created as a session bean?
You can reference spring session beans with the following syntax in your EL in the jsp.
${sessionScope['scopedTarget.messageUtil'].flashMessages}
That calls getFlashMessages() on this bean
<bean id="messageUtil" class="mypackage.MessageUtilImpl" scope="session">
<aop:scoped-proxy proxy-target-class="false"/>
<property name="messageSource" ref="messageSource" />
</bean>
Spring beans are not visible in the views (JSPs in your case) unless you add them first to the model.
You have to add your sessionBean to the model in the controller to make it available to the view.
model.addAttribute("sessionBean", sessionBean);

Resources