Announcement Announcement Module
Collapse
No announcement yet.
HORRIBLE Problem with TransactionProxyFactoryBean Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • HORRIBLE Problem with TransactionProxyFactoryBean

    Hello Everyone:

    I am having a truly gruesome problem with TransactionProxyFactoryBean, and I need some help rather badly. I have used declarative transactions before, and I had a hard time getting everything to work right then. This time, I seem to be totally screwed.

    I am using Hibernate 2.x, Spring 1.0 (also have tried 1.1.5), MySQL, Tomcat 4.1.x. At the moment I am trying to use the prototypical TransactionProxyFactoryBean config, like this:

    * snip *
    <!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate.Hibernate TransactionManager">
    <property name="sessionFactory"><ref bean="sessionFactory"/></property>
    </bean>

    <!-- Transaction manager that delegates to JTA (for a transactional JNDI DataSource) -->
    <!-- <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTran sactionManager"/> -->

    <!-- Transactional proxy for CustomerDAO -->
    <bean id="customerDAO" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
    <property name="transactionManager"><ref bean="transactionManager"/></property>
    <property name="target"><ref bean="customerDAOTarget"/></property>
    <property name="transactionAttributes">
    <props>
    <prop key="*">PROPAGATION_REQUIRED</prop>
    </props>
    </property>
    </bean>

    <!-- customerDAO: Hibernate implementation -->
    <bean id="customerDAOTarget" class="com.foo.orm.dao.CustomerDAO">
    <property name="sessionFactory"><ref bean="sessionFactory"/></property>
    </bean>

    The above bean config fragment (which is an EXCERPT) is read into my bean factory with the following code:

    ClassPathResource res = new ClassPathResource("hibernate-beans.xml");
    beanFactory = new XmlBeanFactory(res);

    Simple, right? But when I try to get a "customerDAO" bean instance with this code:

    CustomerDAO customerDAO = (CustomerDAO) getBean("customerDAO");

    I get the WRONG CLASS - "$Proxy0" is returned by the bean factory instead of a CustomerDAO instance. Then the above "getBean" statement throws ClassCastException because the wrong type is being cast.

    Please toss me a bone. This is a pretty weird problem, and it definitely seems like this ought to work. I have struggled with this for about a day in various forms, and I am really stuck.

  • #2
    You are almost there!

    Seems that your CustomerDAO is a concrete implementation class. What the TransactionProxyFactoryBean do by default is to perform some dynamic proxy trick for your *interfaces* implemented by the specified class. Without any interface, that pretty cute $Proxy0 is largely useless. That also means $Proxy0 will never be the concrete class and any attempt to cast it back to the concrete class will result in ClassCastException.

    The usual practice is to use a CustomerDAO interface, with methods such as load(), save(), etc. Then, add a class CustomerDAOImpl to implement the CustomerDAO interface, let CustomerDAOImpl be the target for the TransactionProxyFactoryBean. After all these, the following line will work:

    Code:
    CustomerDAO customerDAO = &#40;CustomerDAO&#41; getBean&#40;"customerDAO"&#41;;
    You can refer to the Spring documentation or other reference materials for more details.

    Lawrence

    Comment


    • #3
      Problem Solved

      Lawrence - thank you for your thoughtful reply. You were right, the problem was that my Middlegen-generated DAO implementation does not use an interface at the required level.

      However, once I upgraded my Spring jar to 1.1.5 with the matching cglib-nodep-2.1-dev.jar, I was able to make use of the "proxyTargetClass" property setting to instruct TransactionProxyFactoryBean to use class targets instead of interface targets. This is a much better solution in this particular case because our code generation scheme is not amenable to having an interface at or near the top of the class hierarchy. The resulting configuration for the declarative transaction beans looks like this:

      Code:
       <bean id="transactionManager"    class="org.springframework.orm.hibernate.HibernateTransactionManager">
          <property name="sessionFactory"><ref bean="sessionFactory"/></property>
        </bean>
      
        <bean id="txProxyTemplate" abstract="true"
              class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
          <property name="transactionManager"><ref local="transactionManager"/></property>
          <property name="proxyTargetClass"><value>true</value></property> 
          <property name="transactionAttributes">
            <props>
              <prop key="add*">PROPAGATION_REQUIRED</prop>
            </props>
          </property>
        </bean>
      	
        <bean id="customerDAO" parent="txProxyTemplate">
          <property name="target">
            <bean class="com.foo.orm.dao.NgvCustomerDAO" />
          </property>
        </bean>
      This works as desired, and provides a decent solution for us as far as code generation goes as well. Now I only have to generate the XML for the mapping file specs and the indiviidual DAO bean defs. This is straightforward to do with our Middlegen scheme.

      Comment

      Working...
      X