Announcement Announcement Module
Collapse
No announcement yet.
ClassCastException with context.getBean in JUnit test case Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • ClassCastException with context.getBean in JUnit test case

    Hello,

    I'm a Spring newbie trying to put together a first working example, so forgive me if my question is stupid.

    I have set up an environment to test basic persistence functionality using hibernate: I have a business object like petclinic's clinic, which I call 'myFacade' in my application context.

    When I do the following in my code (which runs as JUnit test case):

    Code:
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/context/business-layer-context.xml");
            BizFacadeInterface facade = (BizFacadeInterface) context.getBean("myFacade");
    I get a ClassCastException as the returned object is a TransactionProxy instead of a HibernateBizFacade.

    Could you point me to my mistake?

    Thanks a lot for your help.

    Kambiz


    Here is my config file

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
    	"http&#58;//www.springframework.org/dtd/spring-beans.dtd">
    
    <beans>
    	<!-- ========================= GENERAL DEFINITIONS ========================= -->
    	<!-- Configurer that replaces $&#123;...&#125; placeholders with values from a properties file -->
    	<!-- &#40;in this case, JDBC-related settings for the dataSource definition below&#41; -->
    	<bean id="propertyConfigurer" 
    		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    		<property name="location">
    			<value>/context/jdbc.properties</value>
    		</property>
    	</bean>
    
    	<!-- ========================= RESOURCE DEFINITIONS ========================= -->
    	<!-- Local DataSource that works in any environment -->
    	<bean id="dataSource" 
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName">
    			<value>org.hsqldb.jdbcDriver</value>
    		</property>
    		<property name="url">
    			<value>$&#123;jdbc.url&#125;</value>
    		</property>
    		<property name="username">
    			<value>$&#123;jdbc.username&#125;</value>
    		</property>
    		<property name="password">
    			<value>$&#123;jdbc.password&#125;</value>
    		</property>
    	</bean>
    
    	<!-- Hibernate SessionFactory -->
    	<bean id="sessionFactory" 
    		class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
    		<property name="dataSource">
    			<ref local="dataSource"/>
    		</property>
    		<property name="mappingDirectoryLocations">
    			<list>
    				<value>classpath&#58;my/domain/</value>
    			</list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">$&#123;hibernate.dialect&#125;</prop>
    			</props>
    		</property>
    	</bean>
    	<!-- Transaction manager for a single Hibernate SessionFactory &#40;alternative to JTA&#41; -->
    	<bean id="transactionManager" 
    		class="org.springframework.orm.hibernate.HibernateTransactionManager">
    		<property name="sessionFactory">
    			<ref local="sessionFactory"/>
    		</property>
    	</bean>
    
    	<!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->
    	<!--
    		- A parent bean definition which is a base definition for transaction proxies.
    		- It is markes as abstract, since it is never supposed to be instantiated itself.
    		- We set shared transaction attributes here, following our naming patterns.
    		- The attributes can still be overridden in child bean definitions.
    		-->
    	<bean id="baseTransactionProxy" 
    		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" 
    		abstract="true">
    		<property name="transactionManager">
    			<ref bean="transactionManager"/>
    		</property>
    		<property name="transactionAttributes">
    			<props>
    				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
    				<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
    				<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
    				<prop key="retrieve*">PROPAGATION_REQUIRED,readOnly</prop>
    				<prop key="store*">PROPAGATION_REQUIRED</prop>
    				<prop key="save*">PROPAGATION_REQUIRED</prop>
    				<prop key="delete*">PROPAGATION_REQUIRED</prop>
    			</props>
    		</property>
    	</bean>
    	<!--
    	  - primary business object&#58; Hibernate implementation, as an inner bean
    		- wrapped by an outer transactional proxy. The two bean definitions could have been
    		- separate, but this is cleaner as ther is no need to ever access the unwrapped object.
        -->
    	<bean id="myFacade" parent="baseTransactionProxy">
    		<property name="target">
    			<bean class="myapp.hibernate.HibernateBizFacade">
    				<property name="sessionFactory">
    					<ref local="sessionFactory"/>
    				</property>
    			</bean>
    		</property>
    	</bean>
    </beans>

  • #2
    It seems that you try to proxy a class instead of an interface.
    In that case you should add
    <property name="proxyTargetClass"><value>true</value></property>
    to the definition of your transaction interceptor

    Andreas

    Comment


    • #3
      Thank you for your hint.

      I tried proxyTargetClass, but, now I have a

      BeanNotOfRequiredTypeException: Bean named 'myFacade' must be of type [myapp.domain.BizFacade], but was actually of type [myapp.hibernate.HibernateBizFacade$$EnhancerByCGLI B$$f6935cca]
      And I looked into spring/samples/petclinic/war/WEB-INF/applicationContext-hibernate.xml and found the same situation as mine:

      Code:
      	<!--
      	  - Petclinic primary business object&#58; Hibernate implementation, as an inner bean
      		- wrapped by an outer transactional proxy. The two bean definitions could have been
      		- separate, but this is cleaner as ther is no need to ever access the unwrapped object.
          -->
      	<bean id="clinic" parent="baseTransactionProxy">
      		<property name="target">
      			<bean class="org.springframework.samples.petclinic.hibernate.HibernateClinic">
      				<property name="sessionFactory"><ref local="sessionFactory"/></property>
      			</bean>
      		</property>
      	</bean>
      petclinic:
      • Clinic is the business object's interface

        HibernateClinic extends HibernateDaoSupport implements Clinic

        the 'target' property of the TransactionProxyFactoryBean is the class HibernateClinic and not the interface Clinic

      my setting:
      • BizFacade is the business object's interface

        HibernateBizFacade extends HibernateDaoSupport implements BizFacade

        the target is the class HibernateBizFacade

      So, where is the difference?

      Thanks

      Kambiz

      Comment


      • #4
        Originally posted by darabi
        BizFacade is the business object's interface

        HibernateBizFacade extends HibernateDaoSupport implements BizFacade

        the target is the class HibernateBizFacade
        Ah, so it is really an interface. In that case you should use

        <property name="proxyInterfaces">
        <list>
        <value>xxx.BizFacadeInterface</value>
        </list>
        </property>

        Replace the interface name with the fully qualified name of your interface.
        The other property I proposed should then be unnecessary.

        Andreas

        Comment


        • #5
          Thanks again, Andreas.

          Applying your changes, the exception message changes to:

          BeanNotOfRequiredTypeException: Bean named 'myFacade' must be of type [myapp.domain.BizFacade], but was actually of type [$Proxy0]
          I think we are back to the original situation. The ClassCastException I mentioned in my first post was thrown, because the instantiated bean was a Proxy instead of a BizFacade.

          I'm stuck, again.

          Comment


          • #6
            I must confess I'm at a loss here
            I don't know why this happens. Maybe you could try to create a more simplistic example in order to find out the cause of that effect.

            BTW: Which version of spring are you using? If not 1.1.1 maybe you should try an update.

            Regards,
            Andreas

            Comment


            • #7
              Kambiz,

              As far as I can tell by what is happening to you, you have forgotten to make your HibernateBizFacade implementation class actually implement your interface BizFacadeInterface. Once you do that, your original setup should work.

              Comment


              • #8
                No, my implementation AND my declarations are correct.


                The problem seems to be related to JUnit. I didn't mention that the whole thing runs as a JUnit test case (gui runner) because I didn't know that it is important.

                But, it seems to be: when run as simple application without using JUnit, everything is fine.

                I'm sure this is again a JUnit classloader problem. JUnit's class loader leads to horrible problems. When I disable dynamic classloading in JUnit (by modifying junit/runner/exclude.properties in my junit.jar), my test case works without any problems.

                I hope people with strange problems in conjunction with JUnit will find this thread because it is very time consuming to pinpoint such problems, as they can manifest themselves in different ways (not always a ClassCastException).

                Many thanks for your help.

                Kambiz

                Comment

                Working...
                X