Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Got Unsatisfied dependency expressed through constructor parameter 0 while learning Spring

Tags:

java

spring

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.

like image 784
Ian Avatar asked May 09 '26 13:05

Ian


1 Answers

-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$ 

Reason

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.

like image 88
Grim Avatar answered May 11 '26 03:05

Grim