Home > Software design >  Unexpected error in spring boot constructor
Unexpected error in spring boot constructor

Time:11-28

I wrote a sample program like below.

@Configuration
public class MyclassName{

    private final List<String> tableIds;

    public MyclassName(
        List<String> tableIds) {
        this.tableIds = tableIds;
    }
}

While running i am getting the below error.

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in MyclassName required a single bean, but 4 were found:
    - spring.sleuth.baggage-keys: defined by method 'baggageKeys' in class path resource [org/springframework/cloud/sleuth/autoconfig/TraceBaggageConfiguration.class]
    - spring.sleuth.local-keys: defined by method 'localKeys' in class path resource [org/springframework/cloud/sleuth/autoconfig/TraceBaggageConfiguration.class]
    - spring.sleuth.propagation-keys: defined by method 'propagationKeys' in class path resource [org/springframework/cloud/sleuth/autoconfig/TraceBaggageConfiguration.class]
    - spring.sleuth.log.slf4j.whitelisted-mdc-keys: defined by method 'whiteListedMDCKeys' in class path resource [org/springframework/cloud/sleuth/autoconfig/TraceBaggageConfiguration.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed


Process finished with exit code 0

We are using sleuth for tracing, so pom.xml has that dependencies aswell. But this is a very basic example, why iam getting this error. Can anyone help on this?

CodePudding user response:

    public MyclassName(
        List<String> tableIds) {
        this.tableIds = tableIds;
    }

This means that your MyclassNames, as a Configuration bean in Spring, needs to inject a bean of type List<String>, it happens that slueth's TraceBaggageConfiguration class defines some beans of type List<String>:

    @org.springframework.context.annotation.Bean({"spring.sleuth.baggage-keys"})
    @org.springframework.boot.context.properties.ConfigurationProperties("spring.sleuth.baggage-keys")
    java.util.List<java.lang.String> baggageKeys() { /* compiled code */ }

    @org.springframework.context.annotation.Bean({"spring.sleuth.local-keys"})
    @org.springframework.boot.context.properties.ConfigurationProperties("spring.sleuth.local-keys")
    java.util.List<java.lang.String> localKeys() { /* compiled code */ }

    @org.springframework.context.annotation.Bean({"spring.sleuth.propagation-keys"})
    @org.springframework.boot.context.properties.ConfigurationProperties("spring.sleuth.propagation-keys")
    java.util.List<java.lang.String> propagationKeys() { /* compiled code */ }

So spring reported an error, did not know which bean to inject. You may need to use Qualifier to specify the injected bean. Or, have you defined the corresponding bean which hash a List<String> type need to be injected? What is List<String> tableIds in your MyclassName? You need to define a Bean like this:

    public MyclassNamesss(
            @Qualifier("test") List<String> tableIds) {
        this.tableIds = tableIds;
    }

    @Bean("test")
    public List<String> myString() {
        return new ArrayList<>();
    }

Or you can use, in this case, the tableId will be null:

    public MyclassName(
            @Autowired(required = false) List<String> tableIds) {
        this.tableIds = tableIds;
    }

CodePudding user response:

The class MyclassName is known to the spring framework.

So spring will try to create an instance of MyclassName by using the constructor:

public MyclassName(List<String> tableIds)

The Parameter 0 of constructor in MyclassName is List<String> tableIds

Spring is trying to provide a value for this parameter but instead of only one available value, it founds 4. So Spring is not intelligent enought to choose one in your place.

The 4 available values are provided by Sleuth and are declared in the TraceBaggageConfiguration.class like follow:

@Bean(BAGGAGE_KEYS)
@ConfigurationProperties(BAGGAGE_KEYS)
List<String> baggageKeys() {...}

@Bean(LOCAL_KEYS)
@ConfigurationProperties(LOCAL_KEYS)
List<String> localKeys()  {...}

@Bean(PROPAGATION_KEYS)
@ConfigurationProperties(PROPAGATION_KEYS)
List<String> propagationKeys()  {...}

@Bean(WHITELISTED_MDC_KEYS)
@ConfigurationProperties(WHITELISTED_MDC_KEYS)
List<String> whiteListedMDCKeys()  {...}

To solve the indecision you need to tell Spring which List<String> you realy want injected in your constructor by using an unique identifier.

First qualify (give an id) to the expected bean

@Bean("myExpectedTableIds")
List<String> myTableIdsProcucerMethod()

Then use the org.springframework.beans.factory.annotation.Qualifier annotation to tell Spring which bean you realy want:

public MyclassName(@Qualifier("myExpectedTableIds") List<String> tableIds)
  • Related