web-dev-qa-db-fra.com

Comment autowire un haricot de type générique <T> au printemps?

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?

55
user3374518

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.

114
Shishir Kumar

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
9
Rishav Basu

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);
1
howard791006

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>

1
zg_spring

Spring 4.0 est la solution avec l'utilisation de l'annotation @Qualifier. J'espère que cela t'aides

0
shikjohari

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

0
Ramkumar S