15

I have a properties class defined like this:

@Validated
@ConfigurationProperties(prefix = "plugin.httpclient")
public class HttpClientProperties {
   ...
}

And a configuration class like this:

@Configuration
@EnableScheduling
public class HttpClientConfiguration {

    private final HttpClientProperties httpClientProperties;

    @Autowired
    public HttpClientConfiguration(HttpClientProperties httpClientProperties) {
        this.httpClientProperties = httpClientProperties;
    }

    ...
}

When starting my spring boot application, I'm getting

Parameter 0 of constructor in x.y.z.config.HttpClientConfiguration required a bean of type 'x.y.z.config.HttpClientProperties' that could not be found.

Is this not a valid use case, or do I have to declare the dependencies some how?

Daniel
  • 2,050
  • 7
  • 31
  • 55

2 Answers2

21

This is a valid use case, however, your HttpClientProperties are not picked up because they're not scanned by the component scanner. You could annotate your HttpClientProperties with @Component:

@Validated
@Component
@ConfigurationProperties(prefix = "plugin.httpclient")
public class HttpClientProperties {
    // ...
}

Another way of doing so (as mentioned by Stephane Nicoll) is by using the @EnableConfigurationProperties() annotation on a Spring configuration class, for example:

@EnableConfigurationProperties(HttpClientProperties.class) // This is the recommended way
@EnableScheduling
public class HttpClientConfiguration {
    // ...
}

This is also described in the Spring boot docs.

g00glen00b
  • 41,995
  • 13
  • 95
  • 133
  • There is still one thing that bothers me though. I have another ConfigurationProperties class that is also not annotated as a Component, but that is autowired into a Component. That works. How come? – Daniel May 05 '17 at 10:55
  • @Daniel there must be another difference then. Either the bean is created inside a configuration class (annotated with `@Bean`) or there is another annotation on the configuration properties class that allows component scanning. – g00glen00b May 05 '17 at 10:59
  • 1
    Actually we don't really recommend to use `@Component` and this is described in the doc already: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-typesafe-configuration-properties – Stephane Nicoll May 05 '17 at 11:07
  • 1
    Realized my issue after reading up on Stephane's, link. My first configuration class (which I created a long time ago) is included with @EnableConfigurationProperties(PluginProperties.class) in my main class. I just have to add the HttpClientProperties.class in there as well – Daniel May 05 '17 at 12:21
  • @StephaneNicoll Unless I'm seriously misreading, the link you provided does encourage using `@Component` along with `@ConfigurationProperties`. See the sentence that begins "_You could shortcut MyConfiguration by making sure AcmeProperties is already a bean, as shown in the following example_". Or if not strictly _encouraging_, it's certainly not _discouraging_ this practice. – Charles Wood Aug 29 '18 at 16:50
  • 2
    Thanks for the feedback, this is a link to `current` so the wording may have changed. The important bits are "Even if the preceding configuration creates a regular bean for AcmeProperties, we recommend that @ConfigurationProperties only deal with the environment and, in particular, does not inject other beans from the context.". By not using `@Component` you make it a bit clearer that this object is special and is not supposed to inject other dependencies. That's what `@EnableConfigurationProperties(ABC.class)` gives you. – Stephane Nicoll Aug 30 '18 at 14:15
  • you can use `@Configuration` on your `HttpClientProperties` file instead of `@Component` – Michael Scott Aug 12 '20 at 14:35
0

In Spring Boot 2.2.1+, add the @ConfigurationPropertiesScan annotation to the application. (Note that this was enabled by default in version 2.2.0.) This will allow all classes annotated with @ConfigurationProperties to be picked up without using @EnableConfigurationProperties or @Component.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;

@SpringBootApplication
@ConfigurationPropertiesScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Also, to generate metadata for the classes annotated with @ConfigurationProperties, which is used by IDEs to provide autocompletion and documentation in application.properties, remember to add the following dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
Unmitigated
  • 76,500
  • 11
  • 62
  • 80