2009-02-02 20 views
35

Sto cercando di usare primavera IoC con un'interfaccia simile a questo:primavera CIO e Generic Tipo interfaccia

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

può scaturire fornire CIO in base al tipo di argomento generico T? Insomma, qualcosa di simile:

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

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

Naturalmente, il mio esempio di cui sopra non funziona:

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) 

mia domanda: è possibile fornire una funzionalità simile con modifiche minime al l'interfaccia o le classi di implementazione? So per esempio che posso usare @Qualifiers, ma voglio mantenere le cose il più semplici possibile.

+1

sembra essere possibile, ora, poiché Spring 4.0. Vedi questo [risposta SO] (http://stackoverflow.com/a/22603321/196533) e l'articolo Spring intitolato [Spring Framework 4.0 e Java Generics] (http://spring.io/blog/2013/12/03/primavera-quadro-4-0-e-java-generici). – chrisjleu

risposta

22

Non credo sia possibile a causa della cancellazione. In genere passati a tipizzato fortemente sotto-interfacce quando si va per full-autowiring:

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

Sul fare questo interruttore abbiamo scoperto che in realtà è piaciuto questo abbastanza bene, perché ci permette di fare "troviamo l'utilizzo" monitoraggio molto meglio, qualcosa che perdi con le interfacce generiche.

+1

E come gestite la duplicazione del codice? Probabilmente hai una classe media che è anche generica, no? Tks –

+0

L'unica duplicazione necessaria è l'interfaccia marker. Ma non stai mostrando le tue lezioni di implementazione, quindi non posso dire se stai facendo qualcosa che non vedo! – krosenvold

+0

L'implementazione si adatterebbe ad un'altra domanda SO :) –

14

non credo che questo è possibile senza Qualifier

malato cercare di mostrare le mie soluzioni con genericDAO, scusate se è un po 'dettagliata

l'interfaccia e la classe di implementazione Definizione

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 definizione del bean spring, notare l'abstract = "true"

<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> 

Usando questa genericDAO senza speciale classe di implementazione

<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> 

preavviso il costruttore-ARG con una classe concreta, se si lavora con la Primavera di annotazione che dovete fare:

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

per distinguere le varie versioni di generico chicco di caffè (notare il qualificatore con riferimento diretto al Beanname)

Utilizzo di questo genericoDAO con implementazione speciale Classe

l'interfaccia e la classe

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 definizione Bean, notare il "padre" di riferimento al genericDAO astratto sopra

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

e l'uso con la primavera annotazione

@Autowired 
private TestHibernateParentDAO ToParentDAO; 
+0

Grande risposta che ha colpito sia l'annotazione che gli usi XML. Questa soluzione ha funzionato per te a lungo termine? Dove ci sono degli inconvenienti nell'usare questa metodologia come poter rintracciare più facilmente il codice (menzionato da Krosenvold nel 1 ° post)? – HipsterZipster

+0

è più un problema di organizzazione/conoscenza, se gli sviluppatori conoscono il processo che funziona, questo metodo generico è sicuramente più difficile da gestire rispetto all'uso delle interfacce (marker) –

3

Non rendere la tua interfaccia generica.Realizza i tuoi metodi, invece:

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

Spero che aiuti.

4

È possibile eseguire questa operazione con cancellazione, se il tipo generico viene completamente reificato in fase di compilazione. In questo caso le informazioni sul tipo sono disponibili tramite:

Class#getGenericInterfaces() 
Class#getGenericSuperclass() 

Questa è la caratteristica principale di Guice che manca in primavera.

0

Quando si esegue questa operazione con determinati livelli di persistenza, Spring Data fa questo per voi. Spring Data è un ottimo strumento per risparmiare tempo e semplificare se si utilizza JPA, Neo4j o MongoDB o qualcos'altro che supporta.

0

Un'altra opzione è quella di annotare l'interfaccia attuazione di fagioli con nome su un lato e di annotare con qualificatore che punta al nome creato sul lato opposto :) Ecco un rapido esempio sto utilizzando nel mio progetto:

public interface IDAO<T> { 

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

classe astratta come predecessore:

public abstract class AbstractHibernateDAO { 

     protected SessionFactory sessionFactory; 

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

Attuazione della classe astratta per l'utente entità:

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

}

E infine l'iniezione di destra implementazione:

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