2010-10-04 15 views
9

Sé que muy a menudo se le pide, pero no puedo encontrar una solución de trabajo:¡Patrón abstracto de DAO y problema de Spring: "El proxy no se puede convertir en ..."!

Ésta es mi AbstractDAO:

public interface AbstractDao<T> 
{ 
    public T get(Serializable id); 
    //other CRUD operations 
} 

y esto es la aplicación de mi 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 
} 

Y esto es el dao de una entidad:

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

Aquí es su implementación:

@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... 
    } 
} 

toda la arquitectura es simple:

interfaz AbstractDao define métodos CRUD simples.

Interfaz PersonDao extiende AbstractDAO sin ningún método de complemento.

clase AbstractDaoJpaImpl define la implementación de JPA de AbstractDao

clase PersonDaoImpl extiende AbstractDaoJpaImpl e implementa PersonDao Y OtherInterface, que añade aditionalMethods() ...

SI, PersonDaoImpl sólo se implementa PersonDao, sin implementar OtherInterface.additionalMethods(), todo funciona bien.

puedo usar

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

en el archivo XML de mi primavera.

PERO, PersonDaoImpl implementa OtherInterface (s), cuando se prueba/marcha, I tiene que emitir el DAO de PersonDao a PersonDaoImpl o OtherInterfaces, tales como:

@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(...)); 
    } 
} 

El problema se produce cuando (PersonDaoImpl) dao, que tiros "proxy no se puede convertir a PersonDaoImpl" excepción:

java.lang.ClassCastException: $Proxy36 cannot be cast to foobar.PersonDaoImpl 
    at foobar.PersonDaoTest.testAdditionalMethod(PersonDaoTest.java:36) 

esto se hace a menudo cuando googleing, todo el mundo sugieren la adición de proxy-target-class="true" a <tx:annotation-driven>:

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

Esto hará uso de CGLIB en lugar del proxy dinámico de JDK.

PERO tiros otra excepción al inicializar la primavera:

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

en el constructor del AbstractDaoJpaImpl:

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

Cada pregunta se detiene aquí, no puedo encontrar ningún trabajo soluciones ahora.

¿Alguien puede darme una solución de trabajo? ¡Muchas gracias!

Medio Ambiente: Primavera-3.0.4, JavaEE-API-6.0, javax.inject, cglib-2.2, hibernación-APP-2,0-api-1.0.0,

Respuesta

12

que se está resolviendo el problema equivocado. Los beans proxiados no están destinados a ser convertidos a las clases originales, de una manera u otra. Eso rompería el punto de la inyección de dependencia. Después de todo: cuando especifica una dependencia como interfaz, está solicitando un bean que cumpla un contrato, pero no los detalles de implementación. Al lanzarlo a la clase original de frijoles se rompe este acoplamiento flojo.

que está diciendo los métodos adicionales están respaldados por una interfaz de llamar OtherInterface, ¿por qué no utilice en su lugar? Después de todo, el proxy implementará todas las interfaces de la clase objetivo, no solo la inyectada.

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

Básicamente se tienen estas opciones (ordenados desde limpio a sucio):

  1. independiente de sus preocupaciones y utilizar granos diferentes para diferentes interfaces de
  2. Crear un meta-interfaz que se extiende OtherInterface y PersonDao y deje que su grano de implementar que metainterface
  3. Echa el bean a la interfaz que necesitas en cualquier momento.
+0

Gracias, debería @Inject OtherInterface otherInterfaceImpl; y prueba contra otherInterfaceImpl. Funciona ! – smallufo

0

sí spring siempre crea clases de proxy y así es como descubrió el tejido no intrusivo y aop por xml config ... intenta buscar ese error en la documentación de primavera. Hay reglas que debes seguir y solucionar.

Cuestiones relacionadas