我知道这经常被问到,但我找不到一个有效的解决方案:
这是我的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.
class AbstractDaoJpaImpl定义了JPA的AbstractDao实现
class PersonDaoImpl扩展AbstractDaoJpaImpl并实现PersonDao AND OtherInterface,它添加了aditionalMethods()…
如果,PersonDaoImpl只实现PersonDao,而不实现OtherInterface.additionalMethods(),一切正常.
我可以用
<tx:annotation-driven transaction-manager="transactionManager" />
在我的spring的XML文件中.
但是,PersonDaoImpl实现了OtherInterface,在测试/运行时,我必须将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抛出“Proxy无法强制转换为PersonDaoImpl”异常时,会出现问题:
java.lang.ClassCastException: $Proxy36 cannot be cast to foobar.PersonDaoImpl
at foobar.PersonDaoTest.testAdditionalMethod(PersonDaoTest.java:36)
这经常被问到googleing时,每个人都建议将proxy-target-class =“true”添加到< tx:annotation-driven> :
<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类可以打破这种松散的耦合.
您说其他方法是由您调用OtherInterface的接口备份的,那么为什么不使用它呢?毕竟,代理将实现所有目标类的接口,而不仅仅是注入的接口.
@Test
public void testAdditionalMethod()
{
OtherInterface oi = (OtherInterface) dao;
System.out.println(oi.additionalMethod(...));
}
基本上你有这些选项(从清洁到脏):
>分开您的顾虑和使用
不同的豆子为不同
接口
>创建一个扩展的元接口
OtherInterface和PersonDao and
让你的bean实现它
metainterface
>将bean转换为接口
你需要在任何特定的时刻.