3

I am trying to integrate spring with hibernate this morning. I want to use spring transaction manager. But getting the below error. The error has something to do with @Trasactional Annotation. If i remove the annotation,im able to get the bean from the spring container.

Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy19 cannot be cast to com.hibernate.dao.EvntDAOImpl
at com.hibernate.action.HibernateAction.main(HibernateAction.java:17)

Im pasting below my source code.

POM.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>hibernate-tutorials</groupId>
<artifactId>hibernate-tutorials</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
    </plugins>
</build>
<properties>
    <spring-framework.version>4.0.3.RELEASE</spring-framework.version>
    <hibernate.version>4.3.5.Final</hibernate.version>
     <slf4j.version>1.7.5</slf4j.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring-framework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${spring-framework.version}</version>
    </dependency>

    <!-- Spring ORM support -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${spring-framework.version}</version>
    </dependency>

    <!-- Logging with SLF4J & LogBack -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc14</artifactId>
        <version>10.2.0.2.0</version>
    </dependency>
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
</dependencies>

Hibernate Configuration

<?xml version="1.0" encoding="UTF-8"?>

http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
</bean>

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="annotatedClasses">
        <list>
            <value>com.hibernate.model.Evnt</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

<bean id="transactionManager"
    class="org.springframework.orm.hibernatey.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

EvntDAOImpl.java

package com.hibernate.dao;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.hibernate.model.Evnt;

@Repository(value="evntDAO")
@Transactional
public class EvntDAOImpl implements EvntDAO {

@Autowired
private SessionFactory sessionFactory;

@Override
public void storeEvnt(Evnt evnt) {

    sessionFactory.getCurrentSession().save(evnt);

}

}

HibernateAction.java

package com.hibernate.action;

import java.util.Date;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.hibernate.dao.EvntDAO;
import com.hibernate.dao.EvntDAOImpl;
import com.hibernate.model.Evnt;

public class HibernateAction {

public static void main(String[] args) {
    ApplicationContext context  = new         ClassPathXmlApplicationContext("applicationContext.xml");

    EvntDAOImpl evntDAO = (EvntDAOImpl) context.getBean("evntDAO");
    Evnt evnt = new Evnt();
    evnt.setTitle("first Event");
    evnt.setDate(new Date());
    evntDAO.storeEvnt(evnt);

    }
}

Thanks in advance...

1 Answer 1

5

The problem is in the place where you are injecting EventDaoImpl.

Just replace

@Autowired EventDaoImpl eventDaoImpl

with

@Autowired EventDao eventDao

wherever you need Spring to autowire the dao.

Or if you are getting the bean from the applicationContext use:

EvntDAO evntDAO = (EvntDAO) context.getBean("evntDAO");

The problem is caused by the fact that the use of @Transactional annotation on the dao's implementation code means that Spring will create a JDK dynamic proxy for it, which cannot be cast to the implementation class. Here is the complete documentation of Spring's AOP capabilities (where the creation of JDK dynamic proxies and CGLib class proxies is fully explained).

What that essentially means is that because of @Transactional, when you call context.getBean("evntDAO") you don't get back your EventDaoImpl (as one would expect), but you actually get back an object whose class is java.lang.reflect.Proxy which has been created by Spring. That proxy object implements EventDao (and therefor can be cast to it) but it's signature has nothing to do with EventDaoImpl (and hence the ClassCastException since it does not extend EventDaoImpl). When a method is called on the proxy various things happen before and/or after the call is actually delegated to EventDaoImpl (what happens before/and or after the actual call to EventDaoImpl is controlled by Spring though the implementation of InvocationHandler).

Sign up to request clarification or add additional context in comments.

2 Comments

Great..It worked.. Can you please elaborate this one "use of @Transactional on the dao's implementation code means that Spring will create a JDK proxy for it".
@BhargavKumarR No problem! I will update my answer later with more info because I am on a mobile device at the moment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.