2010-10-04 26 views
9

我知道這是很經常有人問,但我不能找到一個可行的解決方案:抽象的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 
} 

這是一個實體的dao:

public interface PersonDao extends AbstractDao<Person> 
{ 
    //empty 
} 

這裏是它的實現:

​​

整個體系結構是簡單的:

接口AbstractDao的定義簡單CRUD方法。

接口PersonDao擴展了AbstractDAO,沒有任何插件方法。

AbstractDaoJpaImpl定義JPA的實現AbstractDao的

PersonDaoImpl延伸AbstractDaoJpaImpl並實現PersonDao的和OtherInterface,增加aditionalMethods() ...

IF,PersonDaoImpl只實現PersonDao的,沒有實現OtherInterface.additionalMethods(),一切工作正常。

我可以在Spring的XML文件中使用

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

BUT,PersonDaoImpl實現OtherInterface(S),當測試/運行,我必須從PersonDao的鑄DAO來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) 

googleing時,這是經常有人問,大家都建議增加proxy-target-class="true"<tx:annotation-driven>

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

這將使使用CGLIB代替JDK的動態代理。在AbstractDaoJpaImpl的構造

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

但初始化春天時,它拋出另一個異常

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

每一個問題到此爲止,我現在找不到任何工作解決方案。

任何人都可以給我一個工作解決方案嗎? 非常感謝!

環境:彈簧3.0.4,JavaEE的-API 6.0,javax.inject,CGLIB-2.2,休眠,JPA-2.0-API-1.0.0,

回答

12

你解決錯誤的問題。代理的豆類並不意味着以某種方式流向原始類別。這將打破依賴注入的整個點。畢竟:當你指定一個依賴關係作爲接口時,你正在請求一個滿足合同的bean,但不是實現細節。將其轉換爲原始的bean類可以打破這種鬆散耦合。

你說的其他方法是由你稱爲OtherInterface的界面支持的,那麼爲什麼不使用它呢?畢竟,代理將實現所有目標類的接口,而不僅僅是注入的接口。

@Test 
public void testAdditionalMethod() 
{ 
    OtherInterface oi = (OtherInterface) dao; 
    System.out.println(oi.additionalMethod(...)); 
} 

基本上你有這些選項(從乾淨的排序,以髒):

  1. 獨立您的關注和使用 不同豆不同 接口
  2. 創建元接口,擴展 OtherInterfacePersonDao和 讓你的bean實現那個 元接口
  3. 將bean投入到您在任何給定時刻需要的接口 。
+0

謝謝,我應該@Inject OtherInterface otherInterfaceImpl;並針對otherInterfaceImpl進行測試。有用 ! – smallufo 2010-10-04 22:49:12

0

是春天總是創建代理類,它是如何實際發現非侵入式編織和aop通過xml配置...嘗試在春季文檔中搜索該錯誤的搜索結果,有沒有規則要遵循和解決。