J'ai un bean Item<T>
qui doit être connecté automatiquement dans une classe @Configuration
.
@Configuration
public class AppConfig {
@Bean
public Item<String> stringItem() {
return new StringItem();
}
@Bean
public Item<Integer> integerItem() {
return new IntegerItem();
}
}
Mais quand j'essaie de @Autowire Item<String>
, j'obtiens l'exception suivante.
"No qualifying bean of type [Item] is defined: expected single matching bean but found 2: stringItem, integerItem"
Comment dois-je autowire le type générique Item<T>
au printemps?
La solution simple consiste à mettre à niveau vers Spring 4.0 car les génériques seront automatiquement considérés comme une forme de @Qualifier
, comme ci-dessous:
@Autowired
private Item<String> strItem; // Injects the stringItem bean
@Autowired
private Item<Integer> intItem; // Injects the integerItem bean
Enfait, vous pouvez même utiliser des génériques imbriqués automatiquement lors de l’injection dans une liste, comme ci-dessous:
// Inject all Item beans as long as they have an <Integer> generic
// Item<String> beans will not appear in this list
@Autowired
private List<Item<Integer>> intItems;
Comment ça marche?
La nouvelle classe ResolvableType
fournit la logique permettant de travailler avec des types génériques. Vous pouvez l’utiliser vous-même pour naviguer facilement et résoudre les informations de type. La plupart des méthodes sur ResolvableType
renverront elles-mêmes une ResolvableType
, par exemple:
// Assuming 'field' refers to 'intItems' above
ResolvableType t1 = ResolvableType.forField(field); // List<Item<Integer>>
ResolvableType t2 = t1.getGeneric(); // Item<Integer>
ResolvableType t3 = t2.getGeneric(); // Integer
Class<?> c = t3.resolve(); // Integer.class
// or more succinctly
Class<?> c = ResolvableType.forField(field).resolveGeneric(0, 0);
Consultez les exemples et tutoriels ci-dessous.
J'espère que cela vous aide.
Si vous ne voulez pas passer à Spring 4, vous devez autoriser le transfert par son nom, comme ci-dessous:
@Autowired
@Qualifier("stringItem")
private Item<String> strItem; // Injects the stringItem bean
@Autowired
@Qualifier("integerItem")
private Item<Integer> intItem; // Injects the integerItem bean
C'est un travail pour moi !!
List<String> listItem= new ArrayList<>();
ResolvableType resolvableType = ResolvableType.forClassWithGenerics(List.class, String.class);
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setTargetType(resolvableType);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
beanDefinition.setAutowireCandidate(true);
DefaultListableBeanFactory bf = (DefaultListableBeanFactory) configurableWebApplicationContext.getBeanFactory();
bf.registerBeanDefinition("your bean name", beanDefinition);
bf.registerSingleton("your bean name", listItem);
La stratégie de transmission automatique de ressort est définie dans votre fichier de migration (application.xml).
si vous ne définissez pas, le type par défaut est Type, printemps injecter utiliser le mécanisme de réflexion JDK.
alors Liste? String? et List? Item ?, le type est le même List.class, alors ressort confus comment injecter.
et comme indiqué ci-dessus, vous devriez pointer @Qualifier pour indiquer au printemps quelle fève il faut injecter.
j'aime le fichier de migration de printemps pour définir le haricot plutôt que l'annotation.
<bean>
<property name="stringItem">
<list>
<....>
</list>
</property>
Spring 4.0 est la solution avec l'utilisation de l'annotation @Qualifier. J'espère que cela t'aides
Je crois que les génériques n’ont rien à voir avec cela ... Si vous injectez deux fèves différentes du même type, vous devez fournir un qualificatif pour aider Spring à les identifier;
... Autre part
@Configuration
@Bean
public Item stringItem() {
return new StringItem();
}
@Bean
public Item integerItem() {
return new IntegerItem();
}
Si vous avez des déclarations non génériques comme celles-ci, vous devez ajouter un qualificatif pour aider Spring à les identifier ...
@Autowired
**@Qualifier("stringItem")**
private Item item1;
@Autowired
**@Qualifier("integerItem")**
private Item item2;
Bien sûr, dans les versions 4 et supérieures, Spring considère les types génériques à travers les résolveurs, ce qui est très cool ...