I hope is there someone who could help me to understand this error.
I have a problem usign Record with @ConfigurationProperties: when I start the application I get this error:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'environmentConstants' defined in file [C:\Workspace-IntelliJ\TEST\record-configuration-properties-test\target\classes\it\test\recordconfigurationpropertiestest\model\EnvironmentConstants.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: {}
In Springboot 3.2.4 with Java 17 I was looking for the correct way to expose configuration values from application.yml.
I need a way to expose them and to be immutable, in a more clean way than using @Value annotation.
I found out it is possible with @ConfigurationProperties annotation and a Record, so to try it I created a new spring project with spring initializer with the only dependencies of spring-boot-starter, spring-boot-starter-test and lombok.
Then I created my configuration:
my application.yml:
app:
constants:
my-constant: 'MyValue'
and my Record:
@ConfigurationProperties("app.constants")
@Component
public record EnvironmentConstants (
String myConstant){
}
and I was expecting, like the tutorial said, to be able to use it everywhere, so I created a test like this:
my test:
@SpringBootTest
@Slf4j
class ConfigurationTest {
@Autowired
private EnvironmentConstants environmentConstants;
@Test
void test(){
log.info("TEst: {}", environmentConstants.myConstant());
}
}
I also tried a few of different configuration but none of them worked correctly. First: I tried to modify my configuration in application.yml like this:
app:
environment-constants:
my-constant: 'MyValue'
Second: I tried to use @EnableConfigurationProperties
and @ConfigurationPropertiesScan
on the Application class or in the Test Class.
Third: I tried to add the dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
I found a lot of documentation about this, but it seems to me I'm doing this correctly, so why is it not working?
StackOverflow old discussion
Baeldung guide
Thank to @andy-wilkinson response I could find the solution. I left here the right configuration for everyone who get stucks in the same problem. Right application.yml
app:
environment-constants:
my-constant: 'MyValue'
Right Record class:
@ConfigurationProperties(prefix = "app.environment-constants")
public record EnvironmentConstants (
String myConstant){
}
My Application.class with the right annotation:
@SpringBootApplication
@ConfigurationPropertiesScan
public class RecordConfigurationPropertiesTestApplication {
public static void main(String[] args) {
SpringApplication.run(RecordConfigurationPropertiesTestApplication.class, args);
}
}
My Test:
@SpringBootTest
@Slf4j
class ConfigurationTest {
@Autowired
private EnvironmentConstants environmentConstants;
@Test
void test(){
log.info("Test: {}", environmentConstants.myConstant());
assertEquals("MyValue", environmentConstants.myConstant());
}
}
If I want to use @EnableConfigurationProperties
instead of @ConfigurationPropertyScan
I need to specify the class. So the Application.class need to be like this:
@SpringBootApplication
@EnableConfigurationProperties({EnvironmentConstants.class})
public class RecordConfigurationPropertiesTestApplication {
public static void main(String[] args) {
SpringApplication.run(RecordConfigurationPropertiesTestApplication.class, args);
}
}
You were close when you tried @EnableConfigurationProperties
and @ConfigurationPropertiesScan
. In addition to using one of those, you also need to remove @Component
from EnvironmentConstants
.
The problem with @Component
is that it results in EnvironmentConstants
being created as a regular Spring bean which then requires a String
bean to be injected for its myConstant
parameter.
If you remove @Component
, an EnvironmentConstants
instance will only be created as a @ConfigurationProperties
bean. The value of myConstant
will then be the value of your app.environment-constants.my-constant
property.