Абстрактный шаблон 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)

это часто спрашивают при поиске в Google, все предлагают добавить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,

Ответы на вопрос(2)

Решение Вопроса

иведения к исходным классам, так или иначе. Это сломало бы весь смысл внедрения зависимости. В конце концов: когда вы указываете зависимость в качестве интерфейса, вы запрашиваете бин, выполняющий контракт, но не детали реализации. Приведение его к исходному классу бобов разрушает эту слабую связь.

Вы говорите, что дополнительные методы поддерживаются интерфейсом, который вы вызываетеOtherInterfaceтак почему бы не использовать это вместо этого? В конце концов, прокси будет реализовывать все интерфейсы целевого класса, а не только внедренный.

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

В основном у вас есть эти параметры (отсортированы от чистого к грязному):

Разделите ваши проблемы и используйте разные компоненты для разных интерфейсовСоздать мета-интерфейс, который расширяетOtherInterface а такжеPersonDao и пусть ваш бин реализует этот метаинтерфейсПриведите bean-компонент к нужному интерфейсу в любой момент.
 smallufo05 окт. 2010 г., 00:49
Спасибо, я должен @Inject OtherInterface otherInterfaceImpl; и проверить против otherInterfaceImpl. Оно работает !

Spring всег созет прокси-классы, и именно так он на самом деле обнаружил не навязчивое переплетение и установил конфигурацию xml ... попробуйте поискать ошибки в документации по Spring, там должны быть правила, которым нужно следовать, и обходные пути.

Ваш ответ на вопрос