90 votes

Le câblage automatique d'une liste à l'aide du schéma util donne lieu à une NoSuchBeanDefinitionException.

J'ai un bean que je veux injecter avec une liste nommée en utilisant l'espace de noms Spring util. <util:list id="myList"> mais Spring recherche plutôt une collection de beans de type String. Mon test cassé est :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ListInjectionTest {

    @Autowired @Qualifier("myList") private List<String> stringList;

    @Test public void testNotNull() {
        TestCase.assertNotNull("stringList not null", stringList);
    }
}

Mon contexte est le suivant :

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:util="http://www.springframework.org/schema/util"
   xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

   <util:list id="myList">
       <value>foo</value>
       <value>bar</value>
   </util:list>

</beans>

Mais j'ai

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [java.lang.String] found for dependency [collection of java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=myList)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:726)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:571)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:412)

Ce qui me laisse perplexe, car je pensais que c'était ainsi que cela devait fonctionner.

171voto

skaffman Points 197885

Cela est dû à une partie plutôt obscure du comportement de @Autowired, spécifiée dans le document 3.11.2. @Autowired :

Il est également possible de fournir tous les d'un type particulier à partir de la ApplicationContext en ajoutant l'annotation à un champ ou à une méthode qui attend un tableau de ce type...

Il en va de même pour les collections typées...

En d'autres termes, en disant @Autowired @Qualifier("myList") List<String> vous demandez en fait "donnez-moi la liste de tous les haricots de type java.lang.String qui ont le qualificatif "maListe".

La solution est mentionnée dans 3.11.3. Ajustement fin de l'autocâblage basé sur les annotations avec des qualificatifs :

Si vous avez l'intention d'exprimer l'injection pilotée par annotation par son nom, n'utilisez pas principalement @Autowired - même s'il est techniquement capable de se référer à un nom de haricot à travers @Qualifier valeurs. Au lieu de cela, préférez la JSR-250 @Resource qui est sémantiquement définie pour identifier un composant cible spécifique par son nom unique, le type déclaré n'est pas pertinent pour le processus de processus.

La conséquence spécifique de cette différence sémantique, les beans qui sont eux-mêmes définis comme une collection ou map ne peuvent pas être injectés via @Autowired puisque la correspondance des types n'est pas ne leur est pas applicable. Utilisez @Resource pour ces haricots, en se référant à le haricot collection/map spécifique par nom unique.

Utilisez donc ceci dans votre test, et cela fonctionne bien :

@Resource(name="myList") private List<String> stringList;

0voto

juliangonzalez Points 2147

Une autre chose qui pourrait se produire est que vous faites un câblage automatique d'une propriété d'un haricot. Dans ce cas, vous n'avez pas besoin de l'auto-câbler, mais simplement de créer la méthode setter et d'utiliser la balise property dans la définition du bean (si vous utilisez xml), par exemple :

<bean id="cleaningUpOldFilesTasklet" class="com.example.mypackage.batch.tasklets.CleanUpOldFilesTasklet">
    <property name="directoriesToClean">
        <list>
            <value>asfs</value>
            <value>fvdvd</value>
            <value>sdfsfcc</value>
            <value>eeerer</value>
            <value>rerrer</value>
        </list>
    </property>
</bean>

Et la classe :

public class CleanUpOldFilesTasklet extends TransferingFilesTasklet implements Tasklet{

private long pastMillisForExpiration;
private final String dateFormat = "MM.dd";
Date currentDate = null;

List<String> directoriesToClean;

public void setDirectoriesToClean(List<String> directories){
    List<String> dirs = new ArrayList<>();
    for(String directory : directories){
        dirs.add(getSanitizedDir(directory));
    }
    this.directoriesToClean = dirs;
}

Tu vois, non. @Autowired annotation dans la classe.

-1voto

bazwilliams Points 196

Si j'utilise JBoss 6.1, j'ai constaté que l'annotation @Resource faisait échouer mon déploiement (détail omis car non pertinent pour la question).

Une alternative générale pour tous les serveurs d'application consiste à utiliser l'annotation @Inject ( JSR-330 ).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X