I'm learning Spring from the book Spring Start Here. Here, I have added 2 beans of the class Parrot into Spring context, and I'm trying to inject the bean Parrot2 into the Person class using auto wiring through a constructor. However, I keep getting the
"Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'beans.Parrot' available: expected single matching bean but found 2: parrot1,parrot2" error. I'm confused how this happened because I didn't think there would be a problem because the Person class constructor parameter matches the parrot2 bean name.
Configuration class:
package config;
import beans.Parrot;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "beans")
public class ProjectConfig {
@Bean
public Parrot parrot1() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
@Bean
public Parrot parrot2() {
Parrot p = new Parrot();
p.setName("Miki");
return p;
}
}
Parrot class:
package beans;
public class Parrot {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Parrot : " + name;
}
Person class:
package beans;
import org.springframework.stereotype.Component;
@Component
public class Person {
private String name = "Ella";
private final Parrot parrot;
public Person(Parrot parrot2) {
this.parrot = parrot2;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Parrot getParrot() {
return parrot;
}
}
Main class:
package main;
import beans.Person;
import config.ProjectConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
var context = new AnnotationConfigApplicationContext(ProjectConfig.class);
Person p = context.getBean(Person.class);
System.out.println("Person's name: " + p.getName());
System.out.println("Person's parrot: " + p.getParrot());
}
}
Error:
Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'beans.Parrot' available: expected single matching bean but found 2: parrot1,parrot2
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'person' defined in file [C:\Users\Ian36\IdeaProjects\BENAS\target\classes\beans\Person.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'beans.Parrot' available: expected single matching bean but found 2: parrot1,parrot2
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:802)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:241)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1191)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:960)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:93)
at main.Main.main(Main.java:9)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'beans.Parrot' available: expected single matching bean but found 2: parrot1,parrot2
at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:218)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1420)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789)
... 14 more
Process finished with exit code 1
I tried using @Qualifier to see if it would change anything but I still got the same error.
-parameter is off by default.
Enable it using the pom (since 3.6.2) or use -Dmaven.compiler.parameters:
<properties>
<maven.compiler.parameters>true</maven.compiler.parameters>
<properties>
You might update eclipse config using rightclick on the project Maven->Update Project ...
You will get this output:
grim@main:~/workspace/xxx$ mvn exec:java -Dexec.mainClass=main.Main -Dmaven.compiler.parameters
[INFO] Scanning for projects...
[WARNING]
[WARNING] Some problems were encountered while building the effective model for aaa:xxx:jar:0.0.1-SNAPSHOT
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-compiler-plugin is missing. @ line 27, column 12
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]
[INFO]
[INFO] ------------------------------< aaa:xxx >-------------------------------
[INFO] Building xxx 0.0.1-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- exec:3.1.1:java (default-cli) @ xxx ---
Person's name: Ella
Person's parrot: Parrot : Miki
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.293 s
[INFO] Finished at: 2024-01-02T18:49:53+01:00
[INFO] ------------------------------------------------------------------------
grim@main:~/workspace/xxx$
Usually the JDK do store the classnames, fieldnames and method-names in the Bytecode NOT store the method/constructor-argument-names. You need guide the compiler to store the method/constructor-argument-names to the bytecode. Only this way spring is able to find the correct candidate for autowiring.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With