J'essaie d'utiliser Spring IoC avec une interface comme celle-ci:
public interface ISimpleService<T> {
void someOp(T t);
T otherOp();
}
Spring peut-il fournir une IoC basée sur l'argument de type générique T? Je veux dire quelque chose comme ça:
public class SpringIocTest {
@Autowired
ISimpleService<Long> longSvc;
@Autowired
ISimpleService<String> strSvc;
//...
}
Bien sûr, mon exemple ci-dessus ne fonctionne pas:
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)
Ma question: est-il possible de fournir une fonctionnalité similaire avec un minimum de modifications de l’interface ou des classes d’implémentation? Je sais par exemple que je peux utiliser @Qualifiers, mais je veux garder les choses aussi simples que possible.
Je ne crois pas que cela soit possible en raison de l'effacement. Nous optons généralement pour des sous-interfaces fortement typées lorsque nous optons pour le câblage automatique:
public interface LongService extends ISimpleService<Long> {}
public interface StringService extends ISimpleService<String> {}
En effectuant ce changement, nous avons constaté que nous l'aimions plutôt bien, car cela nous permet de mieux "suivre l'utilisation", ce que vous perdez avec les interfaces génériques.
je ne pense pas que ce soit possible sans Qualifier
malade essayer de montrer mes solutions avec un genericDAO, désolé si c'est un peu détaillé
la définition d'interface et de classe d'implémentation
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 définition de haricot de printemps, notez le résumé = "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>
Utilisation de ce genericDAO sans implémentation spéciale Classe
<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>
remarquez le constructeur-arg avec une classe concrète. Si vous travaillez avec Spring Annotation, vous devez effectuer les tâches suivantes:
@Autowired
@Qualifier(value = "testHibernateChildDao")
private GenericDAO<TOChild, Integer> ToChildDAO;
distinguer les différentes versions de genericDao Beans (notez le qualificatif avec référence directe au nom du bean)
Utilisation de ce genericDAO avec une classe d'implémentation spéciale
l'interface et 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 définition de haricot, notez la référence "parent" à l'abrégé genericDAO ci-dessus
<bean id="testHibernateParentDao" class="de.optimum24.av.pers.test.hibernate.dao.TestHibernateParentDAOImpl"
parent="genericHibernateDAO" />
et utilisation avec Spring Annotation
@Autowired
private TestHibernateParentDAO ToParentDAO;
Il est possible de le faire avec effacement si le type générique est complètement réifié au moment de la compilation. Dans ce cas, les informations de type sont disponibles via:
Class#getGenericInterfaces()
Class#getGenericSuperclass()
C'est la principale caractéristique de Guice qui manque au printemps.
Ne faites pas votre interface générique. Faites vos méthodes, à la place:
public interface ISimpleService {
public <T> T doSomething(T param);
}
J'espère que ça aide.
Lorsque vous faites cela avec certaines couches de persistance, Spring Data le fait pour vous. Spring Data est un très bon outil de gain de temps et de simplification si vous utilisez JPA, Neo4j ou MongoDB, ou autre chose qu’il prend en charge.
Une autre option consiste à annoter l'interface implémentant le bean avec name d'un côté et à annoter avec un qualificatif pointant sur le nom créé de l'autre côté :) Voici un exemple rapide que j'utilise dans mon projet:
public interface IDAO<T> {
public void insert(T model);
public void update(T model);
public void delete(T model);
}
Classe abstraite en tant que prédécesseur:
public abstract class AbstractHibernateDAO {
protected SessionFactory sessionFactory;
protected Session currentSession() {
return sessionFactory.getCurrentSession();
}
}
Implémentation d'une classe abstraite pour un utilisateur d'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);
}
}
Et enfin, en injectant la bonne mise en œuvre:
@Resource
@Qualifier(value = "userRepository")
IDAO<User> userPersistence;