2009-02-02 16 views
35

Estoy tratando de utilizar la primavera COI con una interfaz de la siguiente manera:primavera COI y la interfaz genérica

public interface ISimpleService<T> { 
    void someOp(T t); 
    T otherOp(); 
} 

puede surgir proporcionar COI basado en el argumento de tipo genérico T? Es decir, algo como esto:

public class SpringIocTest { 
    @Autowired 
    ISimpleService<Long> longSvc; 

    @Autowired 
    ISimpleService<String> strSvc; 
    //... 
} 

Por supuesto, mi ejemplo anterior no funciona:

expected single matching bean but found 2: [serviceLong, serviceString] 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessAfterInstantiation(AutowiredAnnotationBeanPostProcessor.java:243) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:957) 

Mi pregunta: ¿es posible proporcionar una funcionalidad similar con modificaciones mínimas a cualquiera de la interfaz o las clases de implementación? Sé, por ejemplo, que puedo usar @Qualifiers, pero quiero que todo sea lo más simple posible.

+1

parece ser posible ahora desde la primavera de 4,0. Vea esto [SO answer] (http://stackoverflow.com/a/22603321/196533) y el artículo de Spring titulado [Spring Framework 4.0 y Java Generics] (http://spring.io/blog/2013/12/03/spring-framework-4-0-and-java-generics). – chrisjleu

Respuesta

22

No creo que esto sea posible debido al borrado. en general, pasamos a establecimiento inflexible sub-interfaces cuando se va para-autowiring completo:

public interface LongService extends ISimpleService<Long> {} 
public interface StringService extends ISimpleService<String> {} 

Al hacer este cambio nos dimos cuenta de que en realidad le gustaba esta bastante bien, ya que nos permite hacer "encontramos el uso de" seguimiento mucho mejor, algo que pierdes con las interfaces genéricas.

+1

¿Y cómo manejas la duplicación de código? Probablemente tenga una clase media que también sea genérica, ¿no? Tks –

+0

La única duplicación necesaria es la interfaz del marcador. ¡Pero no muestras tus clases de implementación, así que no puedo decir si estás haciendo algo que no estoy viendo! – krosenvold

+0

La implementación se adecuaría a otra pregunta SO :) –

14

no creo que eso es posible sin Calificador

malos tratar de mostrar mis soluciones con un genericDAO, lo siento si es un poco detallada

la interfaz y Clase de implementación Definición

public interface GenericDAO<T, ID extends Serializable> (...) 

public class GenericDAOImpl<T, ID extends Serializable> 
    implements GenericDAO<T, ID> 
    (...) important is this constructor 
    public GenericDAOImpl(Class<T> persistentClass) { 
     this.persistentClass = persistentClass; 
    } 

la definición del grano de primavera, observe el resumen = "verdadero"

<bean id="genericHibernateDAO" class="de.optimum24.av.pers.ext.hibernate.dao.GenericDAOImpl" 
     abstract="true"> 
    <description> 
     <![CDATA[ 
      Definition des GenericDAO. 
     ]]> 
    </description> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 

El uso de este genericDAO sin clase especial de ejecución

<bean id="testHibernateChildDao" class="de.optimum24.av.pers.ext.hibernate.dao.GenericDAOImpl"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
    <constructor-arg> 
     <value>de.optimum24.av.pers.test.hibernate.domain.TOChild</value> 
    </constructor-arg> 
</bean> 

notificación al constructor-Arg con una clase concreta, si se trabaja con la primavera de anotación que hay que hacer:

@Autowired 
@Qualifier(value = "testHibernateChildDao") 
private GenericDAO<TOChild, Integer> ToChildDAO; 

para distinguir las diferentes versiones de generic Beans Porfavor (observe el calificador con referencia directa al nombre de Bean)

Uso de esteDAO genérico con implementación especial Clase

la interfaz y clase

public interface TestHibernateParentDAO extends GenericDAO<TOParent, Integer>{ 
    void foo(); 
} 
public class TestHibernateParentDAOImpl extends GenericDAOImpl<TOParent, Integer> 
           implements TestHibernateParentDAO { 
    @Override 
    public void foo() { 
     //* no-op */ 
    } 
} 

la Definición de la haba, observe el "padre" de referencia a la genericDAO abstracta por encima de

<bean id="testHibernateParentDao" class="de.optimum24.av.pers.test.hibernate.dao.TestHibernateParentDAOImpl" 
     parent="genericHibernateDAO" /> 

y su uso con la primavera de anotación

@Autowired 
private TestHibernateParentDAO ToParentDAO; 
+0

Gran respuesta para los usos de anotación y XML. ¿Te funcionó esta solución a largo plazo? ¿Dónde hay inconvenientes para usar esta metodología, como ser capaz de rastrear a través del código más fácilmente (mencionado por Krosenvold en la primera publicación)? – HipsterZipster

+0

es más un problema de organización/conocimiento, si los desarrolladores saben que el proceso funciona, este método genérico es ciertamente más difícil de manejar que el uso de interfaces (marcadoras) –

3

No hagas que tu interfaz sea genérica.Haga sus métodos, en su lugar:

public interface ISimpleService { 
    public <T> T doSomething(T param); 
} 

Espero que ayude.

4

Es posible hacer esto con borrado, si el tipo genérico está completamente reificado en tiempo de compilación. En este caso, la información de tipo está disponible a través de cualquiera de:

Class#getGenericInterfaces() 
Class#getGenericSuperclass() 

Esta es la característica principal de Guice que falta en Spring.

0

Al hacer esto con ciertas capas de persistencia, Spring Data hace esto por usted. Spring Data es una gran herramienta de ahorro de tiempo y simplificación si está utilizando JPA, o Neo4j, o MongoDB, o cualquier otra cosa que admita.

0

Otra opción es realizar anotaciones en el interfaz de la aplicación de frijol con el nombre de un lado y anotar con calificador que apunta a nombre creado en el otro lado :) Aquí está un ejemplo rápido que estoy utilizando en mi proyecto:

public interface IDAO<T> { 

     public void insert(T model); 
     public void update(T model); 
     public void delete(T model); 
    } 

clase abstracta como predecesor:

public abstract class AbstractHibernateDAO { 

     protected SessionFactory sessionFactory; 

     protected Session currentSession() { 
      return sessionFactory.getCurrentSession(); 
     } 
    } 

Implementación de clase abstracta para el usuario entidad:

@Repository(value = "userRepository") 
public class UserDAO extends AbstractHibernateDAO implements IDAO<User> { 

    @Autowired 
    public UserDAO(SessionFactory sessionFactory) { 
     this.sessionFactory = sessionFactory; 
    } 

    @Override 
    public void insert(User user) { 
     currentSession().save(user); 
    } 

    @Override 
    public void update(User user) { 
     currentSession().update(user); 
    } 

    @Override 
    public void delete(User user) { 
     currentSession().delete(user); 
    } 

}

Y, finalmente, la inyección de aplicación derecha:

@Resource 
@Qualifier(value = "userRepository") 
IDAO<User> userPersistence; 
Cuestiones relacionadas