Context loader control with Phased interface in Spring - spring

I am trying to take under control the context loading process. As I can read in Spring reference documentation I determined to use Phased interface provided by Spring.
When starting, the objects with the lowest phase start first, and when
stopping, the reverse order is followed. Therefore, an object that
implements SmartLifecycle and whose getPhase() method returns
Integer.MIN_VALUE would be among the first to start and the last to
stop. At the other end of the spectrum, a phase value of
Integer.MAX_VALUE would indicate that the object should be started
last and stopped first (likely because it depends on other processes
to be running). When considering the phase value, it’s also important
to know that the default phase for any "normal" Lifecycle object that
does not implement SmartLifecycle would be 0. Therefore, any negative
phase value would indicate that an object should start before those
standard components (and stop after them), and vice versa for any
positive phase value.
public interface Phased {
int getPhase();
}
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
Only I want load two controllers in phased after all others have been initialized.
To achieve this behaviour I have implemented the Phased Interface in both Spring Components.
#Service to be initialized at firstly.
#Service
public class BatchTaskController implements Phased{
#Autowired
private ActorService actorService;
#Autowired
private SessionFactory sessionFactory;
public BatchTaskController(){
this.batch();
}
public void batch(){
//TO DO...
}
#Override
public int getPhase() {
return 1;
}
}
#Controller to be initialized after batch task #Service.
#Controller
public class MainController implements Phased{
#Autowired
private ActorService actorService;
#Autowired
private SessionFactory sessionFactory;
#RequestMapping(value = {"/", "/index"})
public String showHome(HttpServletRequest request) {
//TO DO
return "index";
}
#Override
public int getPhase() {
return 2;
}
}
ActorService #Service not implement Phased Interface. Therefore I guess as I could read in the Spring Reference article exposed above that ActorService #Service is starting before than previous #Controllers because ActorService #Service phase valor was 0 by default.
But, when I deploy my app i get the next NullPointerException error.
04-04-2014 08:34:10,286 AM ERROR ContextLoader:331 - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'batchTaskController' defined in file [E:\Desarrollo\Spring\pjcomspringehcache\target\pjcomspringehcache-1.0-SNAPSHOT\WEB-INF\classes\com\pjcom\pjcomspringehcache\BatchTaskController.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.pjcom.pjcomspringehcache.BatchTaskController]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1076)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1021)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4738)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5158)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:726)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:702)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:697)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:579)
at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1744)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.uti
l.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:744)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.pjcom.pjcomspringehcache.BatchTaskController]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:164)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1069)
... 26 more
Caused by: java.lang.NullPointerException
at com.pjcom.pjcomspringehcache.BatchTaskController.batch(BatchTaskController.java:32)
at com.pjcom.pjcomspringehcache.BatchTaskController.<init>(BatchTaskController.java:23)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
... 28 more
Why?
SOLUTION
#Service to be initialized at firstly.
#Service
public class BatchTaskController implements Phased{
#Autowired
private ActorService actorService;
#Autowired
private SessionFactory sessionFactory;
#PostConstruct
public void batch(){
//TO DO...
}
#Override
public int getPhase() {
return 1;
}
}

Related

BeanCurrentlyInCreationException when spring starts

I am getting the BeanCurrentlyInCreationException when I start my spring application.
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.datayes.bdb.rrp.business.service.impl.StockModelBaseService com.datayes.bdb.rrp.business.service.impl.StockModelV3ServiceImpl.stockModelBaseService; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'stockModelBaseService': Bean with name 'stockModelBaseService' has been injected into other beans [researchFrameworkCommonServiceImpl] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 71 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'stockModelBaseService': Bean with name 'stockModelBaseService' has been injected into other beans [researchFrameworkCommonServiceImpl] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:568)
And here are the code snippets I have found caused this issue:
#Component public class KafkaConsumerServer implements MessageListener<String, String> {
#Autowired StockModelV3Service stockModelV3Service;
#Autowired FinanceIndicatorService financeIndicatorService;
......
}
#Service public class FinanceIndicatorServiceImpl implements FinanceIndicatorService {
#Autowired StockModelV3Service stockModelV3Service;
#Autowired IndustryResearchFrameworkService industryResearchFrameworkService;
......
}
#Service public class IndustryResearchFrameworkServiceImpl implements IndustryResearchFrameworkService {
#Autowired ResearchFrameworkCommonService commonService;
......
}
#Service public class ResearchFrameworkCommonServiceImpl implements ResearchFrameworkCommonService {
#Autowired StockModelBaseService stockModelBaseService;
......
}
I found some thing interesting in the following article may have explained why.
https://blog.imaginea.com/spring-bean-creation-is-not-thread-safe/
As both my StockModelV3Service and FinanceIndicatorService depends on stockModelBaseService(FinanceIndicatorService -> industryResearchFrameworkService -> researchFrameworkCommonService -> stockModelBaseService), during spring bean creation, they have raced against each other. Which caused BeanCurrentlyInCreationException. As the above article noted, spring bean creation is not thread safe.
To solve this problem seems easy. I changed autowire order as below:
public class KafkaConsumerServer implements MessageListener<String, String> {
#Autowired FinanceIndicatorService financeIndicatorService;
#Autowired StockModelV3Service stockModelV3Service;
As FinanceIndicatorService also depends on StockModelV3Service, so when financeIndicatorService is loaded, it will wait till stockModelV3Service is loaded then load itself. Thus avoid BeanCurrentlyInCreationException.
After all, it has nothing to do with circular reference. As StockModelBaseService doesn't depends on other services.

Spring NullPointerException while injecting Map

I am trying to inject a Map into a UtilityClass. I have created a Map Bean and I am injecting it using #Resource annotation.
#Configuration
class MyConfiguration {
#Bean
Map<String, String> testMap(){
def map = [:] // Using groovy
// Putting things into map
map
}
}
#Component
class MyUtilityClass {
#Resource(name="testMap")
Map<String, String> testMap
}
I am getting following error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testMap' defined in com.my.company.config.MyConfiguration: Initialization of bean failed; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547) ~[spring-beans-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) ~[spring-beans-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) ~[spring-beans-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.1.5.RELEASE.jar:4.1.5.RELEASE]
.....
Caused by: java.lang.NullPointerException
at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:571) ~[spring-core-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:490) ~[spring-core-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:474) ~[spring-core-4.1.5.RELEASE.jar:4.1.5.RELEASE]
Am I doing something wrong here while injecting the Map. Not sure why the NPE is caused?
UPDATE -
So created a class and added the Map as an attribute of that class. And injected that class as a Bean. It worked correctly and it could inject the Class with the Map in it.
#Configuration
class MyConfiguration {
#Bean
Testclass testClass(){
def map = [:] // Using groovy
// Putting things into map
new TestClass(testMap: map)
}
}
class TestClass {
Map<String, String> testMap
}
So seems like the issue is in the Map being injected.

A ServletContext is required to configure default servlet handling

I am trying to figure out a issue for some days but no luck. I came across this issue but not able figure out what is the problem since i am not doing any test here. java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultServletHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'defaultServletHandlerMapping' threw exception; nested exception is java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1119) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1014) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
I am using spring boot
#ComponentScan
#EnableAutoConfiguration
public class Application {
.....
}
public class ApplicationWebXml extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
#Configuration
#AutoConfigureAfter
public class WebConfigurer implements ServletContextInitializer, EmbeddedServletContainerCustomizer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
initCachingHttpHeadersFilter(servletContext, disps);
initStaticResourcesProductionFilter(servletContext, disps);
initGzipFilter(servletContext, disps);
}
Now the problem is coming in TypeToJsonMetadataConverter bean definition in the following #Configuration classes.
#Configuration
public class EntityRestMvcConfiguration extends RepositoryRestMvcConfiguration {
#Bean
public TypeToJsonMetadataConverter typeToJsonMetadataConverter() {
return new TypeToJsonMetadataConverter(typeConfiguration(),
entityLinks());
}
#Bean
public TypeConfiguration typeConfiguration() {
return new TypeConfiguration();
}
}

can I use xml wire with java annotation in spring

I have a class of GenerateKey which is for spring mvc boot. Since it needs to contact database and message queue, so I tried to wire it using xml
#RestController
public class GenerateKey {
final private DriverManagerDataSource dataSource;
final private AmqpTemplate rabbitMQTemplate;
final private String queueName;
public GenerateKey(DriverManagerDataSource dataSource,AmqpTemplate rabbitMQTemplate,String queueName){
this.dataSource=dataSource;
this.rabbitMQTemplate =rabbitMQTemplate;
this.queueName =queueName;
}
#RequestMapping("/key/generate")
public String generateKey(#RequestParam(value = "businesskey") String businesskey, #RequestParam(value = "customer") String customer, Model model) {
JdbcTemplate jdbctemplate = new JdbcTemplate(dataSource);
JSONObject obj = new JSONObject();
obj.put("businesskey", businesskey);
obj.put("customer", customer);
rabbitMQTemplate.convertAndSend(queueName, obj.toString());
System.out.println(businesskey+customer);
return "greeting" + businesskey + customer;
}
}
the xml configurations is as the following and using
#ImportResource( { "rabbit-listener-context.xml" } )
to import it
<bean id="request" class="com.testcom.keyservice.GenerateKey" c:dataSource-ref="dataSource" c:rabbitMQTemplate-ref="keyRequestTemplate" c:queueName="${keyRequestQueueName}"/>
but it complain "No default constructor found" as following:
2014-11-26 21:42:16.095 INFO 17400 --- [ main] utoConfigurationReportLoggingInitializer :
Error starting ApplicationContext. To display the auto-configuration report enabled debug logging (start with --debug)
2014-11-26 21:42:16.097 ERROR 17400 --- [ main] o.s.boot.SpringApplication : Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'generateKey' defined in file [/home/oracle/NetBeansProjects/rabbitmq-native/keyService/build/classes/main/com/testcom/keyservice/GenerateKey.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.testcom.keyservice.GenerateKey]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.testcom.keyservice.GenerateKey.<init>()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1040)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
Exception in thread "main" at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicatixt.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
Since you are using Spring Boot I assume you have also #ComponentScan active in your application. Because of that you create two instances of GenerateKey class - once because of #RestController annotation, second time in XML. I believe that's not what you want to achieve.
Get rid of XML declaration of request bean representing GeneratorKey class and use only Java based autowiring.
#RestController
public class GenerateKey {
private final DriverManagerDataSource dataSource;
private final AmqpTemplate rabbitMQTemplate;
private final String queueName;
#Autowired
public GenerateKey(#Qualifier("dataSource") DriverManagerDataSource dataSource, #Qualifier("keyRequestTemplate") AmqpTemplate rabbitMQTemplate, #Value("${keyRequestQueueName}") String queueName) {
this.dataSource=dataSource;
this.rabbitMQTemplate =rabbitMQTemplate;
this.queueName =queueName;
}

Spring error when trying to manage several classes that share a common base class?

Im currently using Spring 3.0.x ..
Im wondering what's wrong with these structures,
where i would like to manage the subclasses but not the parent classes.
I have 2 child DAOs extending the BaseDAO :
public abstract class BaseDAO<K, E> {
....
}
#Repository
public class UserDAO extends BaseDAO<String, User> {
....
}
#Repository
public class ApprovalDAO extends BaseDAO<String, Approval> {
....
}
And i have the services like this, with hierarchies like this :
public abstract class BaseService<K, E extends BaseEntity, D extends BaseDAO<K, E>> {
#Autowired
protected D dao;
....
}
public abstract class BaseCommonService<K, E extends BaseCommonEntity, D extends BaseDAO<K, E>> extends BaseService<K,E,D> {
....
}
#Service
public class UserService extends BaseCommonService<String, User, UserDAO> {
....
}
When trying to inject the userservice object to my application, it throws error like this :
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name
'testEntities': Injection of autowired
dependencies failed; nested exception
is
org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private
com.primetech.module.common.service.UserService
com.primetech.module.purchase.app.TestEntities.userService;
nested exception is
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name
'userService': Injection of autowired
dependencies failed; nested exception
is
org.springframework.beans.factory.BeanCreationException:
Could not autowire field: protected
com.primetech.core.parent.BaseDAO
com.primetech.core.parent.BaseService.dao;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type
[com.primetech.core.parent.BaseDAO] is
defined: expected single matching bean
but found 2: [userDAO, approvalDAO]
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1064)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:574)
at
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at
org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139)
at
org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:93)
at
com.primetech.module.purchase.app.TestEntities.main(TestEntities.java:81)
Caused by:
org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private
com.primetech.module.common.service.UserService
com.primetech.module.purchase.app.TestEntities.userService;
nested exception is
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name
'userService': Injection of autowired
dependencies failed; nested exception
is
org.springframework.beans.factory.BeanCreationException:
Could not autowire field: protected
com.primetech.core.parent.BaseDAO
com.primetech.core.parent.BaseService.dao;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type
[com.primetech.core.parent.BaseDAO] is
defined: expected single matching bean
but found 2: [userDAO, approvalDAO]
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:507)
at
org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:283)
... 13 more Caused by:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name
'userService': Injection of autowired
dependencies failed; nested exception
is
org.springframework.beans.factory.BeanCreationException:
Could not autowire field: protected
com.primetech.core.parent.BaseDAO
com.primetech.core.parent.BaseService.dao;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type
[com.primetech.core.parent.BaseDAO] is
defined: expected single matching bean
but found 2: [userDAO, approvalDAO]
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1064)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:838)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:780)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:697)
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
... 15 more Caused by:
org.springframework.beans.factory.BeanCreationException:
Could not autowire field: protected
com.primetech.core.parent.BaseDAO
com.primetech.core.parent.BaseService.dao;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type
[com.primetech.core.parent.BaseDAO] is
defined: expected single matching bean
but found 2: [userDAO, approvalDAO]
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:507)
at
org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:283)
... 26 more Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type
[com.primetech.core.parent.BaseDAO] is
defined: expected single matching bean
but found 2: [userDAO, approvalDAO]
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:790)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:697)
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
... 28 more
I tried changing this section, removing the #Repository annotation :
#Repository
public class ApprovalDAO extends BaseDAO<String, Approval> {
....
}
into this :
public class ApprovalDAO extends BaseDAO<String, Approval> {
....
}
And things run without error, but then, the approvalDAO isnt managed by the spring anymore, and cannot be injected later by #Autowired
Any suggestions on how i can solve this problem ?
Autowiring works only if there is exactly one implementation bean of the specific type present in the Spring Context. I'd assume that using the generic D extends BaseDao leads to a situation where Spring is trying to autowire instances of BaseDao instead of UserDao and ApprovalDao. Because you both UserDao and ApprovalDao implement BaseDao, Spring context contains multiple implementations of BaseDao and cannot decide which one should be used.
Spring is trying to tell this to you in the stack trace
org.springframework.beans.factory.NoSuchBeanDefinitionException:
__No unique bean of type__ [com.primetech.core.parent.BaseDAO] is defined:
expected single matching bean but found 2: [userDAO, approvalDAO]
You could try to test this by defining the dao in the concrete service using the actual dao type e.g.
public abstract class BaseService<K, E extends BaseEntity, D extends BaseDAO<K, E>> {
private final D dao;
protected BaseService(D dao) {
this.dao = dao;
}
}
public class UserService extends BaseService<K, User, UserDao<K, User>> {
#Autowired
public UserService(UserDao dao) {
super(dao);
}
}
I'd continue by defining interfaces for UserDao and ApprovalDao so that dependencies are on interfaces and not implementations. The daos may still have a common super interface and their implementations may be based on the BaseDao to avoid unnecessary duplication.
In the example I've defined the injected Dao in the constructor because I assume that the same dao instance should be used throughout the lifetime of the service and the service cannot exist without the dao set. In my opinion, a constructor argument communicates this contract better. Furthermore it might make the class a bit more testable and maintainable.

Resources