View Full Version : getBean from within a proxied bean
ndijkstra
Sep 6th, 2004, 09:15 PM
Hi i'm having the following problem
Given the following classes:
- StudentDao -> target of TransactionProxyFactoryBean
- SequenceDao -> idem StudentDao
SequenceDao is used from StudentDao to obtain the next value in a sequece for autoincremental primary key value. The problem is that when i call getBean from the ApplicationContext i get a Proxy object that can't be casted to SequenceDao because a ClassCastException is thrown. Can somebody tell me what's wrong?
When obtained with getBean from outside StudentDao, the SequenceDao proxy can be casted without exceptions being thrown
Rod Johnson
Sep 7th, 2004, 01:02 AM
Can you please post class definitions (without the body code) and config, so it's easier to figure out what's going on and I can reproduce this scenario? I can't see any potential cause of a problem so far...
ndijkstra
Sep 7th, 2004, 07:13 AM
Here goes the code
applicationContext.xml
<beans>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyP laceholderConfigurer">
<property name="locations">
<list>
<value>WEB-INF/jdbc.properties</value>
</list>
</property>
</bean>
<bean id="citFacade" class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="target">
<bean class="com.sep.padron.business.facade.CITFacade">
<property name="entityDao">
<ref bean="entityDao"/>
</property>
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED,-com.sep.padron.business.exception.SystemException</prop>
</props>
</property>
</bean>
<bean id="sequenceDao" class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="target">
<ref bean="sequenceDaoTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRES_NEW</prop>
</props>
</property>
</bean>
</beans>
dataAccessContext.xml
<beans>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>${dataSource.jndiName}</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTran sactionManager">
<property name="dataSource">
<ref local="dataSource"/>
</property>
</bean>
<bean id="sqlMap" class="org.springframework.orm.ibatis.SqlMapFactoryBean">
<property name="configLocation">
<value>/WEB-INF/sql-map-config.xml</value>
</property>
</bean>
<bean id="entityDao" class="com.sep.padron.persistence.ibatis.SqlMapEntityDao">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="sqlMap">
<ref local="sqlMap"/>
</property>
<property name="sequenceDaoName">
<value>sequenceDao</value>
</property>
</bean>
<!-- Sequence generator -->
<bean id="sequenceDaoTarget" class="com.sep.padron.persistence.ibatis.SqlMapSequenceDa o">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="sqlMap">
<ref local="sqlMap"/>
</property>
</bean>
</beans>
SqlMapSequenceDao
public class SqlMapSequenceDao extends SqlMapDaoSupport implements SequenceDAO{
public Integer getNextValue(String sequenceName){
// fetch next sequence value from 'SEQUENCE' table
}
}
SqlMapEntityDao
public class SqlMapEntityDao extends SequenceDependentDao implements EntityDAO{
public String insertRow(Entity entity) {
entity.setEntityId(
super.getSequenceDao().getNextValue("C_ENTIDAD.ENTIDAD_ID").toString());
super.getSqlMapTemplate().executeUpdate("insertEntity", entity);
return entity.getEntityId();
}
}
SequenceDependentDao
1 -public class SequenceDependentDao extends SqlMapDaoSupport implements ApplicationContextAware{
2 - private String sequenceDaoName;
3 - private ApplicationContext applicationContext;
4 -
5 - public SqlMapSequenceDao getSequenceDao(){
6 - return (SqlMapSequenceDao) this.applicationContext.getBean(this.sequenceDaoNa me);
7 - }
8 -
9 - public void setSequenceDaoName(String sequenceDaoName){
10- this.sequenceDaoName = sequenceDaoName;
11- }
12-
13- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
14- this.applicationContext = applicationContext;
15- }
16-}
In line 6 is where i get a ClassCastException because the object returned by getBean is an instance of Proxy
I hope this can help you help me :P
Rod Johnson
Sep 7th, 2004, 07:32 AM
Thanks. The problem is that you're trying to cast the proxy to SqlMapSequenceDao, which is a class. By default Spring AOP uses JDK dynamic proxies, which can only proxy interfaces. Thus your proxy is only implementing the interface SequenceDAO. The AOP framework assumes that you won't try to cast to the actual implementing class.
You can easily do what you want to do. You simply need to force the TransactionProxyFactoryBean to use CGLIB proxying, by setting its "proxyTargetClass" property to true. You will then need to add the CGLIB Jar from the Spring distribution to your application classpath, if it's not there already (for example, if you use Hibernate as well as Spring).
Rgds
Rod
ndijkstra
Sep 7th, 2004, 07:50 AM
Rod, thank you very much.
It finally worked.
Powered by vBulletin® Version 4.2.1 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.