Friday, April 21, 2017

Can't Autowire a Bean which is present in a dependent Jar

Leave a Comment

I have tried this solution found in the following questions, but none work in my case:

@Configuration @EnableWebMvc @ComponentScan("myapp.framework.export") public class WebConfig extends MyAppWebConfig {      @Override     public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {          super.configureContentNegotiation(configurer);      }      @Override     public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {          super.configureMessageConverters(converters);      }  } 

Error:

INFO: Initializing Spring FrameworkServlet 'services-rest' 2017-04-11 15:25:52,774|localhost-startStop-1|NO_TID|NO_USER|ERROR|org.springframework.web.servlet.DispatcherServlet.initServletBean|Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xlsHttpMessageConverter': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'myapp.framework.export.ExportXlsModelService<?>[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.annotation.Resource(shareable=true, lookup=, name=, description=, authenticationType=CONTAINER, type=class java.lang.Object, mappedName=)}     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:321)     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)     at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:668)     at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:634)     at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:682)     at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:553)     at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:494)     at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:138)     at javax.servlet.GenericServlet.init(GenericServlet.java:158)     at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1241)     at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1154)     at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1041)     at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4969)     at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5255)     at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)     at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)     at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)     at java.util.concurrent.FutureTask.run(FutureTask.java:266)     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)     at java.lang.Thread.run(Thread.java:745) Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'myapp.framework.export.ExportXlsModelService<?>[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.annotation.Resource(shareable=true, lookup=, name=, description=, authenticationType=CONTAINER, type=class java.lang.Object, mappedName=)}     at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1486)     at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)     at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:518)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:496)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:627)     at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169)     at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:318)     ... 29 common frames omitted  Apr 11, 2017 3:25:52 PM org.apache.catalina.core.ApplicationContext log SEVERE: StandardWrapper.Throwable org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xlsHttpMessageConverter': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'myapp.framework.export.ExportXlsModelService<?>[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.annotation.Resource(shareable=true, lookup=, name=, description=, authenticationType=CONTAINER, type=class java.lang.Object, mappedName=)}     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:321)     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)     at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:668)     at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:634)     at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:682)     at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:553)     at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:494)     at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:138)     at javax.servlet.GenericServlet.init(GenericServlet.java:158)     at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1241)     at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1154)     at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1041)     at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4969)     at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5255)     at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)     at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)     at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)     at java.util.concurrent.FutureTask.run(FutureTask.java:266)     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)     at java.lang.Thread.run(Thread.java:745) Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'myapp.framework.export.ExportXlsModelService<?>[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.annotation.Resource(shareable=true, lookup=, name=, description=, authenticationType=CONTAINER, type=class java.lang.Object, mappedName=)}     at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1486)     at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)     at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:518)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:496)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:627)     at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169)     at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:318)     ... 29 more  Apr 11, 2017 3:25:52 PM org.apache.catalina.core.StandardContext loadOnStartup SEVERE: Servlet /myapp threw load() exception org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'myapp.framework.export.ExportXlsModelService<?>[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.annotation.Resource(shareable=true, lookup=, name=, description=, authenticationType=CONTAINER, type=class java.lang.Object, mappedName=)}     at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1486)     at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)     at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:518)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:496)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:627)     at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169)     at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)     at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:318)     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)     at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:668)     at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:634)     at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:682)     at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:553)     at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:494)     at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:138)     at javax.servlet.GenericServlet.init(GenericServlet.java:158)     at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1241)     at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1154)     at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1041)     at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4969)     at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5255)     at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)     at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)     at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)     at java.util.concurrent.FutureTask.run(FutureTask.java:266)     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)     at java.lang.Thread.run(Thread.java:745)  Apr 11, 2017 3:25:52 PM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["http-nio-8080"] Apr 11, 2017 3:25:52 PM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["ajp-nio-8009"] Apr 11, 2017 3:25:52 PM org.apache.catalina.startup.Catalina start INFO: Server startup in 10565 ms 

xlsHttpMessageConverter:

package myapp.framework.web.converter;  import myapp.framework.export.ExportXlsModelService;  import java.io.IOException; import java.io.OutputStream;  import javax.annotation.Resource;  import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.stereotype.Service;     @Service     public class XlsHttpMessageConverter<T> extends                 AbstractMyAppHttpMessageConverter<T, ExportXlsModelService<T>> {          @Resource         private ExportXlsModelService<T>[] exportServices;          public XlsHttpMessageConverter() {              super(MyAppMediaType.APPLICATION_EXCEL);         }          @Override         protected void ecrireFichier(final T toExport, final OutputStream os) throws IOException,             HttpMessageNotWritableException {              final ExportXlsModelService<T> exportService = getServiceExport(toExport);              final HSSFWorkbook model = exportService.construireXlsModel(toExport);             model.write(os);         }          @Override         protected ExportXlsModelService<T>[] getServicesExport() {              return exportServices;         }      } 

5 Answers

Answers 1

Try to add classpath*: Prefix to your scan. (read here)

The * means scan in all jars on classpath

UPDATE:

Your converter has package myapp.framework.web.converter but scan checks myapp.framework.export

Answers 2

Spring is unable to find the implementation for ExportXlsModelService interface.

 public interface ExportXlsModelService<T> extends ExportModelService<T> {     public HSSFWorkbook construireXlsModel(T toExport); } 

Something like

@Service public class ExportXlsModelServiceImpl1 implements  ExportXlsModelService<Model> {     @Override     public HSSFWorkbook construireXlsModel(Model toExport) {         // implementation goes here     } }   @Service     public class ExportXlsModelServiceImpl2 implements  ExportXlsModelService<Model> {      @Override      public HSSFWorkbook construireXlsModel(Model toExport) {          // implementation goes here     } } 

Answers 3

I think there is issue in autowiring as Generic class. We have to specify particular Type while autowiring.

Following Reference may be useful:

  1. Reference1
  2. Reference2

Answers 4

You can't have a @Service that has a type parameter T, how would Spring know what T should be when it instantiates the bean.

If you have 5 different XlsHttpMessageConverter<T>, you have to declare 5 beans. Unfortunately even if you define each converter as a separate bean, there is no way for Spring to know which ExportXlsModelService<T>[] exportServices; to inject, as it will consider all ExportXlsModelService as candidate regardless of the type parameter (see edit below).

It is however possible to inject a bean of a specific type into a @Bean method, so the following example works (but is very impractical for large number of types).

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;  import java.util.List;  import static org.junit.Assert.assertNotNull;  @Configuration public class MyConfig {      public static void main(String[] args) {          AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);          ConverterInjectionTarget bean = ctx.getBean(ConverterInjectionTarget.class);         System.out.println("injected Converters = " + bean.converters.size());         for (XlsHttpMessageConverter converter : bean.converters) {             assertNotNull(converter.value);         }     }      // correct version of generic bean can be autowired into @Bean method     @Bean     XlsHttpMessageConverter integerConverter(Injectable<Integer> value) {         return new XlsHttpMessageConverter<>(value);     }      @Bean     XlsHttpMessageConverter StringConverter(Injectable<String> value) {         return new XlsHttpMessageConverter<String>(value);     }      @Bean     Injectable<Integer> integerDummyBean() {         return new Injectable<>(1);     }      @Bean     Injectable<String> stringDummyBean() {         return new Injectable<>("hello");     }      @Bean     ConverterInjectionTarget myBean() {         return new ConverterInjectionTarget();     }      static class XlsHttpMessageConverter<T> {         // impossible to autowire this, it has to be set through the constructor         final Injectable<T> value;          XlsHttpMessageConverter(Injectable<T> value) {             this.value = value;         }     }      static class ConverterInjectionTarget {         @Autowired         List<XlsHttpMessageConverter> converters;     }      class Injectable<T> {         final T value;          Injectable(T value) {             this.value = value;         }     } } 

If you modify the example and try to autowire the Injectable into XlsHttpMessageConverter you will see that it fails.

The best solution may be to create a BeanFactoryPostProcessor that will create all the ExportXlsModelService instances programmatically, and provide them as input to the XlsHttpMessageConverter instances, which are then registered as singletons.

EDIT One thing I did not mention, is that it is possible to autowire a generic type, but it requires that the bean is defined as a concrete class (not using a @Bean method), so the following would also work (multiple files).

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;  import java.util.List;  import static org.junit.Assert.assertNotNull;  @Configuration @ComponentScan("myPackage") public class MyConfig {      public static void main(String[] args) {          AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);          ConverterInjectionTarget bean = ctx.getBean(ConverterInjectionTarget.class);         System.out.println("injected Converters = " + bean.converters.size());         for (XlsHttpMessageConverter converter : bean.converters) {             assertNotNull(converter.value);         }     }      @Bean     Injectable<Integer> integerDummyBean() {         return new Injectable<>(1);     }      @Bean     Injectable<String> stringDummyBean() {         return new Injectable<>("hello");     }      @Bean     ConverterInjectionTarget myBean() {         return new ConverterInjectionTarget();     }      static class ConverterInjectionTarget {         @Autowired         List<XlsHttpMessageConverter> converters;     }      static class Injectable<T> {         final T value;          Injectable(T value) {             this.value = value;         }     } }  abstract class  XlsHttpMessageConverter<T> {     // this is possible to autowire because we have a concrete class that spring can read the bytecode from.     @Autowired     MyConfig.Injectable<T> value; }  @Service public class IntegerXlsHttpMessageConverter<T> extends XlsHttpMessageConverter<Integer> { }  @Service public class StringXlsHttpMessageConverter extends XlsHttpMessageConverter<String> { } 

But again this may not be feasible if there are many types.

Answers 5

Did you try using @Import, if the dependent jar has some @Configuration classes, that defines the bean use @Import for aggregating configurations. Link

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment