वसंत में जेनेरिक प्रकार <टी> के बीन को ऑटोवेयर कैसे करें?


83

मेरे पास एक बीन है Item<T>जिसे एक @Configurationकक्षा में स्वत: प्राप्त करना आवश्यक है ।

@Configuration
public class AppConfig {

    @Bean
    public Item<String> stringItem() {
        return new StringItem();
    }

    @Bean
    public Item<Integer> integerItem() {
        return new IntegerItem();
    }

}

लेकिन जब मैं करने की कोशिश करता @Autowire Item<String>हूं, तो मुझे निम्नलिखित अपवाद मिलते हैं।

"No qualifying bean of type [Item] is defined: expected single matching bean but found 2: stringItem, integerItem"

मुझे Item<T>स्प्रिंग में जेनरिक प्रकार कैसे ऑटो करना चाहिए ?

जवाबों:


145

सरल उपाय स्प्रिंग 4.0 में अपग्रेड करना है क्योंकि यह नीचे दिए गए अनुसार स्वचालित रूप से जेनरिक के रूप में विचार करेगा @Qualifier:

@Autowired
private Item<String> strItem; // Injects the stringItem bean

@Autowired
private Item<Integer> intItem; // Injects the integerItem bean

वास्तव में, आप नीचे सूचीबद्ध के रूप में सूची में इंजेक्ट करते समय नेस्टेड नैटिक्स को भी स्वायत्त कर सकते हैं:

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

यह कैसे काम करता है?

नया ResolvableTypeवर्ग वास्तव में जेनेरिक प्रकारों के साथ काम करने का तर्क प्रदान करता है। आप आसानी से नेविगेट करने और प्रकार की जानकारी को हल करने के लिए इसका उपयोग कर सकते हैं। उदाहरण के लिए, अधिकांश विधियाँ ResolvableTypeस्वयं ही वापस आ जाएंगी ResolvableType:

// 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);

नीचे दिए गए लिंक पर उदाहरण और ट्यूटोरियल देखें।

आशा है कि यह आपकी मदद करता है।


11
ये अद्भुत है। मुझे लगा कि टाइप एरासुर ने इस तरह की चीज को संभव नहीं बनाया है।
जॉन स्ट्राइकर

6
मैं बीनफैक्ट्री से रिज़ोल्वेबिल्टी द्वारा बीन कैसे प्राप्त कर सकता हूं?
ceram1

@ जॉन्स्ट्रिकलर मुझे भी लगा कि यह सुरक्षित रूप से नहीं किया जा सकता। मैंने अभी तक ResolvableType के कार्यान्वयन की जाँच नहीं की है, लेकिन क्या इसका मतलब है कि हम सुरक्षित रूप से अब सामान्य प्रकार प्राप्त कर सकते हैं?
xi.lin

2
वास्तव में कुछ मामलों में आप जावा में रनटाइम में सामान्य प्रकार प्राप्त कर सकते हैं। एक शर्त, आपको सामान्य वर्ग का उपवर्ग होना चाहिए। उदाहरण: अभिभावक वर्ग public class Parent<T> {}उपवर्ग public class Child extends Parent<Integer> { }और अब: Child c = new Child(); System.out.println(((ParameterizedType)c.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);प्रिंट करेंगेclass java.lang.Integer
मिशैल प्रिज्ब्य्लक

1
क्या यह पैकेज-स्कैन बीन ऑटोकॉन्फ़िगरेशन के साथ काम करेगा? मुझे ऐसा नहीं लगता।
प्रेस्लेव रचेव

12

यदि आप स्प्रिंग 4 में अपग्रेड नहीं करना चाहते हैं, तो आपको नीचे दिए गए नाम से ऑटोवॉयर करना होगा:

@Autowired
@Qualifier("stringItem")
private Item<String> strItem; // Injects the stringItem bean

@Autowired
@Qualifier("integerItem")
private Item<Integer> intItem; // Injects the integerItem bean

क्या आप सीधे ठोस StringItemऔर IntegerItemकक्षाओं के साथ काम करना चाहते हैं?
user3374518

2

नीचे इस सवाल का जवाब देने के लिए एक समाधान है:


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

स्प्रिंग 5+ में बीटीडब्लू
हावर्ड791006

1

स्प्रिंग ऑटोव्हर्ड रणनीति आपकी विन्यास फाइल (application.xml) में परिभाषित की गई है।

यदि आप परिभाषित नहीं करते हैं, तो डिफ़ॉल्ट प्रकार से है, वसंत इंजेक्शन JDK प्रतिबिंबित तंत्र का उपयोग करें।

इतनी सूची? स्ट्रिंग? और सूची? आइटम ?, प्रकार एक ही List.class है, इसलिए वसंत कैसे भ्रमित करने के लिए इंजेक्शन।

और उपरोक्त व्यक्तियों की प्रतिक्रिया के रूप में, आपको वसंत को बताने के लिए @Qualifier को इंगित करना चाहिए जो बीन इंजेक्ट किया जाना चाहिए।

मैं बीन को परिभाषित करने के लिए स्प्रिंग कॉन्फ़िगरेशन फ़ाइल पसंद करता हूं बल्कि एनोटेशन।

<bean>
 <property name="stringItem">
        <list>
              <....>
        </list>
 </property>


0

स्प्रिंग 4.0 @Qualifier एनोटेशन उपयोग के साथ उत्तर है। उम्मीद है की यह मदद करेगा


0

मेरा मानना ​​है कि इसका जेनरिक से कोई लेना-देना नहीं है ... यदि आप एक ही प्रकार की दो अलग-अलग फलियों को इंजेक्ट कर रहे हैं, तो आपको स्प्रिंग को पहचानने में मदद करने के लिए एक क्वालीफायर प्रदान करना होगा;

... कहीं और

@Configuration
@Bean
public Item stringItem() {
    return new StringItem();
}

@Bean
public Item integerItem() {
    return new IntegerItem();
}

यदि आपके पास इन जैसे गैर-सामान्य घोषणाएं हैं, तो आपको वसंत को पहचानने में मदद करने के लिए क्वालीफायर जोड़ने की आवश्यकता है ...

@Autowired
**@Qualifier("stringItem")**
private Item item1;

@Autowired
**@Qualifier("integerItem")**
private Item item2;

बेशक, संस्करण 4 और इसके बाद के संस्करण के वसंत रिज़ॉल्वर के माध्यम से जेनेरिक प्रकारों पर विचार करते हैं जो बहुत अच्छा है ...

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.