Announcement Announcement Module
Collapse
No announcement yet.
Problem with @Transactional + implement a generic interface? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem with @Transactional + implement a generic interface?

    Hi!

    My first message in this community

    I'm having issues when configuring Spring + Hibernate.

    I have an interface HibernateDao<T> :

    Code:
    public interface HibernateDao<T> extends Dao<T> {
    
        public void setSessionFactory(SessionFactory sessionFactory);
    
        public List<T> getAll();
    
        public T get(Integer id);
        
        public T insert(T add);
    
        public T update(T update);
        
        public void delete(Integer id);
    
        public Integer getCount();
    
        public T getNext(Integer previousId);
        
        public List<T> getRange(Integer startRow, Integer endRow, Ordenacion[] sortBy,
    	    Map<String, Object> filterCriteria);
    
    }
    Then, the concrete DAO classes implements that interface and the @Transactional annotations in the methods.

    Code:
    public class ActividadDAOHibernate implements HibernateDao<Actividad> {
    
        private SessionFactory sessionFactory;
    
        @Override
        public void setSessionFactory(SessionFactory sessionFactory) {
            this.sessionFactory = sessionFactory;
        }
    
        @SuppressWarnings("unchecked")
        @Override
        @Transactional(readOnly=true)
        public List<Actividad> getAll() {
            return (List<Actividad>) sessionFactory.getCurrentSession()
                .createCriteria(Actividad.class).list();
        }
    
        @Override
        @Transactional(readOnly=true)
        public Actividad get(Integer id) {
            return (Actividad) sessionFactory.getCurrentSession().get(
                Actividad.class, id);
        }
    
        @Override
        @Transactional
        public Actividad insert(Actividad add) {
            Integer id = (Integer) sessionFactory.getCurrentSession().save(add);
            add.setId(id);
            return add;
        }
    
    //...
    }
    Here is my configuration XML:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
    
        <context:property-placeholder location="classpath:env.properties" />
    
        <!--========== TransactionManager ========== -->
    
        <bean id="txManager"
            class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>
    
        <!-- ========= Para usar @Transactional =========== -->
        <tx:annotation-driven transaction-manager="txManager" />
    
        <!--========== /TransactionManager ========== -->
    
        <!--========== Hibernate SessionFactory ========== -->
    
        <bean id="sessionFactory"
            class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"><!-- <property name="dataSource"> <ref bean="dataSource" /> </property> -->
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.connection.driver_class">${hibernate.connection.driver_class}</prop>
                    <prop key="hibernate.connection.password">${hibernate.connection.password}</prop>
                    <prop key="hibernate.connection.url">${hibernate.connection.url}</prop>
                    <prop key="hibernate.connection.username">${hibernate.connection.username}</prop>
                    <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                    <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                    <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                    <prop key="current_session_context_class">${hibernate.current_session_context_class}</prop>
                </props>
            </property>
    
            <property name="annotatedClasses">
                <list>
                    <value>es.aevum.gwt.aevumerp.shared.domain.Actividad</value>
                </list>
            </property>
    
        </bean>
    
    	<bean id="actividadDao"
    		class="es.aevum.gwt.aevumerp.server.persistence.dao.hibernate.ActividadDAOHibernate">
    		<property name="sessionFactory" ref="sessionFactory" />
    	</bean>
    </beans>
    Finally I have this this test:
    Code:
    public class ActividadDAOHibernateTest {
    
        private static ApplicationContext ctx;
        private static ActividadDAOHibernate dao;
    
        @BeforeClass
        public static void setUpBeforeClass() throws Exception {
            ctx = new ClassPathXmlApplicationContext("beans.xml");
            Object o = ctx.getBean("actividadDao");
            dao = (ActividadDAOHibernate) o;
        
        }
    
        @Test
        public void testGetAll() {
            List<Actividad> list = dao.getAll();
            assertNotNull(list);
            assertEquals("Se espera una lista con dos elementos", 2, list.size());
        }
    
        @Test
        public void testGet() {
            Actividad act = dao.get(1);
            assertNotNull(act);
            assertEquals("Se espera que el id sea 1", new Integer(1), act.getId());
            assertEquals("Se espera que el código sea 1", new Integer(1), act.getCodigo());
            assertEquals("Se espera que el nombre sea act1", "act1", act.getNombre());
        }

    When I execute the test I get this exception in the @BeforeClass method:
    Code:
    java.lang.ClassCastException: $Proxy12 cannot be cast to es.aevum.gwt.aevumerp.server.persistence.dao.hibernate.ActividadDAOHibernate
        at es.aevum.gwt.aevumerp.server.persistence.dao.hibernate.ActividadDAOHibernateTest.setUpBeforeClass(ActividadDAOHibernateTest.java:23)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    Well, I know that if I configure the annotation-driven this way:
    Code:
    <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
    then the problem is solved.

    The problem is that without the proxy-target-class="true" I only get the exception IF THE HibernateDao<T> INTERFACE HAVE THE GENERIC TYPE (T).
    If my DAO doesn't implement any interface or if the interface doesn't have the generic type (i.e. HibernateDao) I don't get the Exception without proxy-target-class="true".

    So, IMHO is probably an issue in the ProxyFactory (¿?) when the Proxied class implements an interface with a Generic Type (:S)

    In addition I would like to implement the @Transactional annotation in the HibernateDao<T> interface, which is not possible with proxy-target-class="true"

    What can I do??

    Thank you!
    - Luis

  • #2
    You shouldn't be programming to concrete classes but interfaces. So instead of using ActividadDAOHibernate you should be using 'HibernateDao<Actividad>' in your test case.

    Generics are a beast especially when you start proxying especially classproxying which relies on cglib which is quite dated and probably doesn't handle generic proxies that well.

    Comment


    • #3
      Thanks a lot! I'll try it next Monday

      Comment


      • #4
        Annotation use to direct to jsp page

        Please help me out in telling me the annotation used to direct from a handler to a jsp page and also the annotation used for application context.

        Also,tell me the way by which I can annotate the property with list of values defined in bean injection xml file.

        Please its urgent.

        I am stuck badly.

        Comment


        • #5
          @marten it works! Thank you

          @shipra.ms I don't understand your question but it seems to not be related with this thread. Open a new one

          Comment

          Working...
          X