Spring 3.0.x - context: component scan to list result

I am wondering if it is possible to move spring beans from a component scan to a list to insert a list into a property?

I am using spring 3.0.x and Java 6 (1.6).

I have tried so far the following:

<util:list id="converterList"> <context:component-scan base-package="com.company.convert"/> </util:list> <!-- configure custom b2bde converters --> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <ref local="converterList"/> </list> </property> </bean> 

But I get the following exception:

 SEVERE: Exception sending context initialized event to listener instance of class de.hybris.platform.spring.HybrisContextLoaderListener org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Incorrect usage of element 'context:component-scan' in a nested manner. This tag cannot be used nested inside <property>. Offending resource: ServletContext resource [/WEB-INF/my-servlet.xml] at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68) at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85) at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:80) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.error(BeanDefinitionParserDelegate.java:284) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseNestedCustomElement(BeanDefinitionParserDelegate.java:1390) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parsePropertySubElement(BeanDefinitionParserDelegate.java:956) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCollectionElements(BeanDefinitionParserDelegate.java:1140) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseListElement(BeanDefinitionParserDelegate.java:1116) at org.springframework.beans.factory.xml.UtilNamespaceHandler$ListBeanDefinitionParser.doParse(UtilNamespaceHandler.java:123) at org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser.parseInternal(AbstractSingleBeanDefinitionParser.java:85) at org.springframework.beans.factory.xml.AbstractBeanDefinitionParser.parse(AbstractBeanDefinitionParser.java:59) at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:73) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1335) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1325) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:135) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:93) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:124) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:93) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:467) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:397) 

Are there enough points or can’t scan the beans, put them in a list and use this list in the property?

Best regards, Walter

+2
source share
3 answers

You will probably never be able to do this in XML, but using Java Config (Spring 3 function), this should be fairly simple using org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.

Updated following comments

Or continue to use the XML <context:component-scan base-package="com.company.convert"/> to register the beans, and then in the Java Configuration use org.springframework.beans.factory.ListableBeanFactory.getBeansOfType(Class<T>) (from the connected ApplicationContext ) to get them all and call setService setter.

+2
source

What works with protection looks something like this:

 Interface Marker{}; @Service class ServiceA implements Marker {...} @Service class ServiceB implements Marker {...} @Service class MyService implements { @Resource private List<Marker> allMarkerImplementations; } 

You can do the same with @Qualifyer instead of Marker interfaces.

 @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface InterestingService {} @InterestingService @Service class ServiceA {...} @InterestingService @Service class ServiceB {...} @Service class MyService implements { @Resource @InterestingService private List<Object> allInterestingServices; } 

This method is useful if you need special beans, if you need EVERYTHING, then I would look for another solution.

+2
source

To complete it, I implemented the following approach:

spring xml config:

 <!-- java config provides the conversionService factory bean --> <bean name="myCompanyJavaConfig" class="com.company.config.MyCompanySpringConfig"/> <!-- scans all converters which will be picked up by the MyCompanySpringConfig and will be registers as list to conversion service--> <context:component-scan base-package="com.company.convert"/> <!-- activates annotation driven binding --> <!-- the conversion service is registered by the java config MyCompanySpringConfig --> <mvc:annotation-driven conversion-service="conversionService" validator="validator"/> 

java config implementation:

 package com.company.config; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ConversionServiceFactoryBean; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; @Configuration public class MyCompanySpringConfig { @Autowired private ApplicationContext applicationContext; public @Bean FactoryBean<ConversionService> conversionService() { ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean(); conversionServiceFactoryBean.setConverters(converters()); return conversionServiceFactoryBean; } public @Bean Set<Converter> converters() { Map<String, Converter> converterBeans = applicationContext.getBeansOfType(Converter.class); return new LinkedHashSet<Converter>(converterBeans.values()); } } 

if this is the perfect way? I do not know ;-), but I know that it works now.

Thanks to all the answers.

Best regards, Walter

+2
source

All Articles