抽象的DAO模式和Spring的“代理不能转换为...”问题!

我知道这经常被问到,但是我找不到可行的解决方案:

这是我的AbstractDAO:

public interface AbstractDao<T>

{

public T get(Serializable id);

//other CRUD operations

}

这是我的JPA的实现:

public abstract class AbstractDaoJpaImpl<T> implements AbstractDao<T> , Serializable

{

protected EntityManager em;

protected Class<T> clazz;

@SuppressWarnings("unchecked")

public AbstractDaoJpaImpl()

{

ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();

this.clazz = (Class<T>) genericSuperclass.getActualTypeArguments()[0];

}

public abstract void setEntityManager(EntityManager em);

//implementations skipped

}

这是一个实体的岛:

public interface PersonDao extends AbstractDao<Person>

{

//empty

}

这是它的实现:

@Repository

public class PersonDaoImpl extends AbstractDaoJpaImpl<Person> implements PersonDao , OtherInterface

{

@PersistenceContext(unitName="company")

@Override

public void setEntityManager(EntityManager em)

{

this.em = em;

}

@Override // implements OtherInterface.additionalMethods()

public additionalMethods()

{

// implements...

}

}

整个架构很简单:

接口AbstractDao定义了简单的CRUD方法。

接口PersonDao扩展了AbstractDAO,而没有任何附加方法。

类AbstractDaoJpaImpl定义JPA对AbstractDao的实现

类PersonDaoImpl扩展AbstractDaoJpaImpl并实现PersonDao 和OtherInterface,这增加了aditionalMethods() …

如果,PersonDaoImpl仅实现PersonDao,而没有实现OtherInterface.additionalMethods(),则一切正常。

我可以用

<tx:annotation-driven transaction-manager="transactionManager" /> 

在我春天的XML文件中。

但是,PersonDaoImpl实现OtherInterface(s),在测试/运行时,我必须将DAO从PersonDao强制转换为PersonDaoImpl或OtherInterfaces,例如:

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations={"classpath:app.xml"})

@TransactionConfiguration(transactionManager="transactionManager" , defaultRollback=false)

public class PersonDaoTest

{

@Inject

PersonDao dao;

@Test

public void testAdditionalMethod()

{

PersonDaoImpl impl = (PersonDaoImpl) dao;

System.out.println(impl.additionalMethod(...));

}

}

当出现时(PersonDaoImpl) dao,会引发问题,该异常引发“代理无法强制转换为PersonDaoImpl”:

java.lang.ClassCastException: $Proxy36 cannot be cast to foobar.PersonDaoImpl

at foobar.PersonDaoTest.testAdditionalMethod(PersonDaoTest.java:36)

谷歌搜索时经常会问到这一点,每个人都建议添加proxy-target-class=”true”到

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"  />

这将使用CGLIB代替JDK的动态代理。

但是在初始化Spring时会引发另一个异常:

Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

在AbstractDaoJpaImpl的构造函数中:

ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();

每个问题都在这里停止,我现在找不到任何可行的解决方案。

谁能给我一个可行的解决方案?非常感谢 !

环境:Spring-3.0.4,javaee-api-6.0,javax.inject,cglib-2.2,hibernate-jpa-2.0-api-1.0.0,

回答:

你正在解决错误的问题。代理的bean并不是要以一种或另一种方式转换为原始类。这将打破依赖注入的全部观点。毕竟:当你将依赖项指定为接口时,你是在请求一个满足合同的Bean,而不是实现详细信息。将其强制转换为原始bean类可以打破这种松散的耦合。

你是说其他方法由你调用的接口备份OtherInterface,那么为什么不使用它呢?毕竟,代理将实现所有目标类的接口,而不仅仅是注入的接口。

@Test

public void testAdditionalMethod()

{

OtherInterface oi = (OtherInterface) dao;

System.out.println(oi.additionalMethod(...));

}

基本上,你可以使用以下选项(从干净到肮脏不等):

  1. 分开你的顾虑并为不同的接口使用不同的bean
  2. 创建延伸的metainterface OtherInterface并PersonDao让你的bean实现一个metainterface
  3. 在任何给定时刻将bean投射到所需的接口。

以上是 抽象的DAO模式和Spring的“代理不能转换为...”问题! 的全部内容, 来源链接: utcz.com/qa/401826.html

回到顶部