In a Spring application, I have used @Autowired(required=false)
on constructor. This means that if the bean that will be autowired is not available in the xml file, no NoSuchBeanDefinitionException
should be thrown as (required=false
) is mentioned. But I am getting the UnsatisfiedDependencyException
, NoSuchBeanDefinitionException
exception.
---- TextEditor
public class TextEditor {
private SpellChecker x;
private String name;
@Autowired(required=false)
public TextEditor(SpellChecker x) {
System.out.println("Inside TextEditor constructor." );
this.x = x;
}
public SpellChecker getY() {
return x;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void spellCheck() {
x.checkSpelling();
}
}
---- SpellChecker
public class SpellChecker {
public SpellChecker() {
System.out.println("Inside SpellChecker constructor.");
}
public void checkSpelling() {
System.out.println("Inside checkSpelling.");
}
}
---- Beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aks="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
aks:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<bean id="textEditor" class="com.tutorialspoint.TextEditor">
<!-- <property name="x" ref="a" /> -->
<property name="name" value="Generic Text Editor" />
</bean>
<!-- <bean id="a" class="com.tutorialspoint.SpellChecker" /> -->
</beans>
---- MainApp
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"Beans.xml");//Beans.xml, Beans1.xml
TextEditor te = (TextEditor) context.getBean("textEditor");
//te.spellCheck();
System.out.println(te.getY());
}
}
--- Console(Actual Result)
Apr 24, 2014 4:30:00 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9: startup date [Thu Apr 24 16:30:00 IST 2014]; root of context hierarchy
Apr 24, 2014 4:30:00 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [Beans.xml]
Apr 24, 2014 4:30:00 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2d9c06: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,textEditor]; root of factory hierarchy
Apr 24, 2014 4:30:00 PM org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2d9c06: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,textEditor]; root of factory hierarchy
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'textEditor' defined in class path resource [Beans.xml]: Unsatisfied dependency expressed through constructor argument with index 0 of type [com.tutorialspoint.SpellChecker]: : No matching bean of type [com.tutorialspoint.SpellChecker] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.tutorialspoint.SpellChecker] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:730)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1002)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:906)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:484)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:455)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
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.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.tutorialspoint.MainApp.main(MainApp.java:8)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.tutorialspoint.SpellChecker] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:924)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:793)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:795)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:723)
... 15 more
--- Expected Result
Program should run without any Exception
as @Autowire(required=false)
is mentioned for the constructor. Even if the bean is not found the exception should not come since (required=false
) is mentioned.
This exception happens because required = false does not mean that it will inject null. When applied to constructors Spring will try to decide which constructor is best suited for creating the instance. In this case you have only one constructor that need a SpellChecker but no object of that type.
As referenced in the Spring doc (http://docs.spring.io/spring/docs/4.0.x/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html):
Only one constructor (at max) of any given bean class may carry this annotation, indicating the constructor to autowire when used as a Spring bean. Such a constructor does not have to be public.
Anyway you can add a default constructor (it can be private) so that when Spring can't do its @Autowired magic it will use that one. In you TextEditor class you could add:
@Deprecated
private TextEditor() {
// You could leave x = null or create a default value for that field
// if you have one (eg. x = new DefaultSpellChecker();)
}
Note that @Deprecated is used to avoid your compiler to warn you that you have a private constructor that no one uses.