Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proxy cannot be cast to CLASS

I'm using Spring for wiring dependencies specifically for DAO classes that use Hibernate, but I'm getting an exception that has me puzzled:

$Proxy58 cannot be cast to UserDao

My DAO is configured as follows:

<bean id="userDao" class="com.domain.app.dao.UserDao">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

And I have an interface, abstract base class and a final implementation as follows.

Interface:

public interface Dao {
    public void save(Object object);
    public Object load(long id);
    public void delete(Object object);
    public void setSessionFactory(SessionFactory sessionFactory);
}

Abstract Base Class:

public abstract class BaseDao implements Dao {

    private SessionFactory sessionFactory;

    @Transactional
    @Override
    public void save(Object object) {
        PersistentEntity obj = (PersistentEntity) object;
        currentSession().saveOrUpdate(obj);
    }

    @Transactional
    @Override
    public abstract Object load(long id);

    @Transactional
    @Override
    public void delete(Object object) {
        // TODO: this method!
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public Session currentSession() {
        return sessionFactory.getCurrentSession();
    }

}

Implementation:

public class UserDao extends BaseDao implements Dao {

    @Transactional(readOnly=true)
    @Override
    public Object load(long id) {
        Object user = currentSession().get(User.class, id);
        return user;
    }

}

The following throws the exception mentioned above:

UserDao dao = (UserDao) context.getBean("userDao");

This, however, does not throw an exception:

Dao dao = (Dao) context.getBean("userDao");

If anyone can offer any assistance or guidance as to why this exception is happening, I would be very appreciative.

like image 202
mchandler Avatar asked Apr 16 '13 21:04

mchandler


2 Answers

Spring uses JDK dynamic proxies by default ($Proxy58 is one of them), that can only proxy interfaces. This means that the dynamically created type $Proxy58 will implement one or more of the interfaces implemented by the wrapped/target class (UserDao), but it won't be an actual subclass of it. That's basically why you can cast the userDao bean to the Dao interface, but not to the UserDao class.

You can use <tx:annotation-driven proxy-target-class="true"/> to instruct Spring to use CGLIB proxies that are actual subclasses of the proxied class, but I think it's better practice to program against interfaces. If you need to access some methods from the proxied class which are not declared in one of it's interfaces, you should ask yourself first, why this is the case?
(Also, in your code above there are no new methods introduced in UserDao, so there is no point in casting the bean to this concrete implementation type anyway.)

See more about different proxying mechanisms in the official Spring reference.

like image 83
zagyi Avatar answered Oct 24 '22 10:10

zagyi


I was writing unit tests and needed to be able to stub out the DAOs for some calls. Per This guys post: http://www.techper.net/2009/06/05/how-to-acess-target-object-behind-a-spring-proxy/ I used his method provided:

@SuppressWarnings({"unchecked"})
protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
  if (AopUtils.isJdkDynamicProxy(proxy)) {
    return (T) ((Advised)proxy).getTargetSource().getTarget();
  } else {
    return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class
  }
}

Then you can easily call it with the proxy and get the object behind the proxy and manipulate the objects in it directly as needed.

like image 42
Uncle Iroh Avatar answered Oct 24 '22 09:10

Uncle Iroh