@Component on a @ConfigurationProperties class causing error with spring boot application

1.3k Views Asked by At

When I run an application with @Component and @ConfigurationProperties("currency-service") on a class and then I have a rest controller and an @RequestMapping which prints the value of its object but when I run the spring application it does not start and throws this error in the console:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.1.0)

2023-06-20T17:40:02.123+05:30  INFO 5452 --- [  restartedMain] c.r.L.LearnSpringBootApplication         : Starting LearnSpringBootApplication using Java 19 with PID 5452 (C:\Learn-Spring-Boot\Learn-Spring-Boot\target\classes started by dkent in C:\Learn-Spring-Boot\Learn-Spring-Boot)
2023-06-20T17:40:02.126+05:30  INFO 5452 --- [  restartedMain] c.r.L.LearnSpringBootApplication         : The following 1 profile is active: "prod"
2023-06-20T17:40:02.175+05:30  INFO 5452 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2023-06-20T17:40:02.176+05:30  INFO 5452 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2023-06-20T17:40:03.057+05:30  INFO 5452 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2023-06-20T17:40:03.066+05:30  INFO 5452 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-06-20T17:40:03.066+05:30  INFO 5452 --- [  restartedMain] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.8]
2023-06-20T17:40:03.124+05:30  INFO 5452 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-06-20T17:40:03.126+05:30  INFO 5452 --- [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 948 ms
2023-06-20T17:40:03.175+05:30  WARN 5452 --- [  restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'currencyServiceConfiguration' defined in file [C:\Learn-Spring-Boot\Learn-Spring-Boot\target\classes\com\ronit\LearnSpringBoot\CurrencyServiceConfiguration.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
2023-06-20T17:40:03.178+05:30  INFO 5452 --- [  restartedMain] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2023-06-20T17:40:03.192+05:30  INFO 5452 --- [  restartedMain] .s.b.a.l.ConditionEvaluationReportLogger : 

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2023-06-20T17:40:03.215+05:30 ERROR 5452 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   : 

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

Description:

CurrencyServiceConfiguration is annotated with @ConstructorBinding but it is defined as a regular bean which caused dependency injection to fail.

Action:

Update your configuration so that CurrencyServiceConfiguration is defined via @ConfigurationPropertiesScan or @EnableConfigurationProperties.

This is my currency configuration class with @Component and @ConfigurationProperties("currency-service") annotation

package com.ronit.LearnSpringBoot;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties("currency-service")
public class CurrencyServiceConfiguration {
     private String url;
    private String username;
    private String key;

    public CurrencyServiceConfiguration(String url, String username, String key) {
        super();
        this.url = url;
        this.username = username;
        this.key = key;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getUrl() {
        return url;
    }

    public String getUsername() {
        return username;
    }

    public String getKey() {
        return key;
    }

}

This is my CurrencyConfigurationController class with @RestController annotation and a method with @RequestMapping annotation

package com.ronit.LearnSpringBoot;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CurrencyServiceController {
    @Autowired
     private CurrencyServiceConfiguration configuration;
@RequestMapping("/currency-configuration")
CurrencyServiceConfiguration retreiveAllCourse(){
return configuration;
}
}

This is the application.properties file:

logging.level.org.springframework = debug;

currency-service.url=http://default.in28minutes.com
currency-service.username=defaultusername
currency-service.username=defaultkey

This is the application class

package com.ronit.LearnSpringBoot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LearnSpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(LearnSpringBootApplication.class, args);
    }

}

I am using jdk 19 java Spring 6 and Spring Boot 3

I have other classes and one more Rest Controller as well but they are working fine the problem started after adding these two files .

Please tell me if more information about anything is required.

2

There are 2 best solutions below

3
On

Do all the following:

  1. Remove the @Component annotation and add @ConstructorBinding to suggest Spring the data binding is done through the constructor.

    @ConstructorBinding
    @ConfigurationProperties("currency-service")
    public class CurrencyServiceConfiguration {
    
        private String url;
        private String username;
        private String key;
    
        // all-args constructor, getters, and setters
    }
    
  2. Add the @EnableConfigurationProperties annotation with the properties configuration (CurrencyServiceConfiguration) to either a configuration or the main application class:

    @SpringBootApplication
    @EnableConfigurationProperties({CurrencyServiceConfiguration.class})
    public class LearnSpringBootApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(LearnSpringBootApplication.class, args);
        }
    }
    
0
On

To use constructor binding the class must be enabled using @EnableConfigurationProperties or configuration property scanning. Constructor binding cannot be used with beans that are created by the regular Spring mechanisms. so

adding @EnableConfigurationProperties to CurrencyServiceConfiguration shall solve your problem.

also application.properties file has currency-service.username assigned twice, you may wanna check this bug too.