9

私はこれが非常に頻繁に尋ねられることを知っています、しかし私は実用的な解決策を見つけることができません:

これは私の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
}

そしてこれは1つのエンティティのdaoです:

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を拡張し、aditionalMethods ()を追加するPersonDaoANDOtherInterfaceを実装します。

、PersonDaoImplはPersonDaoのみを実装し、OtherInterface.additionalMethods()を実装しない場合、すべてが正常に機能します。

使うことができます

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

私の春の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、「プロキシを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>ます:

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

これにより、JDKの動的プロキシの代わりにCGLIBが使用されます。

しかし、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、

4

2 に答える 2

12

あなたは間違った問題を解決しています。プロキシされたBeanは、いずれかの方法で元のクラスにキャストされることを意図したものではありません。それは依存性注入の全体的なポイントを壊すでしょう。結局のところ、インターフェースとして依存関係を指定すると、契約を履行するBeanを要求しますが、実装の詳細は要求しません。元のBeanクラスにキャストすると、この緩い結合が壊れます。

追加のメソッドは、呼び出すインターフェイスによってバックアップされると言っているOtherInterfaceので、代わりにそれを使用してみませんか?結局のところ、プロキシは、注入されたものだけでなく、すべてのターゲットクラスのインターフェイスを実装します。

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

基本的に、次のオプションがあります(クリーンからダーティにソート):

  1. 懸念事項を分離し、インターフェイスごとに異なるBeanを使用します
  2. 拡張するメタインターフェースを作成し 、BeanにそのメタインターフェースOtherInterfacePersonDao実装させます
  3. いつでも必要なインターフェースにBeanをキャストします。
于 2010-10-04T07:26:00.760 に答える
0

はい、springは常にプロキシクラスを作成します。これにより、xmlconfigによって非侵入型のウィービングとaopが実際に検出されました...Springのドキュメントでそのエラーをグーグルで調べてみてください。従うべきルールと回避策があります。

于 2011-04-07T13:34:04.340 に答える