Pengkabelan otomatis Daftar menggunakan skema util memberikan NoSuchBeanDefinitionException

90

Saya memiliki kacang yang ingin saya masukkan dengan daftar bernama menggunakan namespace util <util:list id="myList">Spring tetapi Spring sedang mencari koleksi kacang jenis String sebagai gantinya. Tes rusak saya adalah:

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

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

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

Konteks saya adalah:

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

Tapi saya mengerti

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)

Yang membuat saya bingung karena saya pikir ini akan menjadi cara yang diharapkan untuk berhasil.

Paul McKenzie
sumber

Jawaban:

171

Hal ini disebabkan oleh bagian yang agak tidak jelas dari perilaku @ Autowired, ditentukan dalam 3.11.2. @Autired :

Dimungkinkan juga untuk menyediakan semua kacang jenis tertentu dari ApplicationContextdengan menambahkan anotasi ke bidang atau metode yang mengharapkan larik jenis itu ...

Hal yang sama berlaku untuk koleksi yang diketik ...

Dengan kata lain, dengan mengatakan @Autowired @Qualifier("myList") List<String>, Anda sebenarnya meminta "beri saya daftar semua jenis kacang java.lang.Stringyang memiliki kualifikasi" myList ".

Solusinya disebutkan dalam 3.11.3. Menyempurnakan pengiriman otomatis berbasis anotasi dengan kualifikasi :

Jika Anda bermaksud untuk mengekspresikan injeksi berdasarkan anotasi berdasarkan nama, jangan gunakan terutama @Autowired- meskipun secara teknis mampu merujuk ke nama kacang melalui @Qualifier nilai. Sebagai gantinya, lebih suka JSR-250 @Resource anotasi yang secara semantik didefinisikan untuk mengidentifikasi komponen target tertentu dengan nama uniknya, dengan tipe yang dideklarasikan tidak relevan untuk proses pencocokan.

Sebagai konsekuensi khusus dari perbedaan semantik ini, kacang yang dengan sendirinya didefinisikan sebagai kumpulan atau tipe peta tidak dapat disuntikkan @Autowiredkarena pencocokan jenis tidak dapat diterapkan dengan benar padanya. Gunakan @Resourcekacang seperti itu, mengacu pada koleksi / peta kacang tertentu dengan nama yang unik.

Jadi gunakan ini dalam pengujian Anda, dan berfungsi dengan baik:

@Resource(name="myList") private List<String> stringList;
skaffman
sumber
9
Anda hidup lebih aman dan begitu pula stackoverflow.com! :)
Rihards
5
Saya akan memberikan sepuluh suara ini jika saya bisa. Anda Da Man, skaffman.
duffymo
3
Fakta bahwa banyak yang bingung dengan ini berarti semantik benar-benar membingungkan. Entah apa alasan di balik desain yang membingungkan tersebut.
supertonsky
3
Wow, saya menganggap Spring sebagai salah satu area terkuat saya dalam pemrograman dan saya belum pernah mengalami masalah ini hingga hari ini dan Anda menghemat banyak waktu saya. Terima kasih!
Avi
2
Adakah saran untuk bagaimana membuat ini bekerja dengan konstruktor / metode injeksi, mengatakan sebagai @Resource tidak mendukung parameter?
cjbooms
0

Hal lain yang bisa terjadi adalah Anda melakukan autowiring properti kacang. Dalam kasus seperti itu Anda tidak perlu melakukan autowire, tetapi cukup buat metode penyetel dan gunakan tag properti dalam contoh definisi kacang (saat menggunakan xml):

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

Dan kelasnya:

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

Lihat, tidak ada @Autowiredanotasi di kelas.

juliangonzalez
sumber