I've run into a weird behavior of Spring Boot (3.1.3) when using -
in property names. Here's the sample code:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootTest
class DemoApplicationTests {
@Value("${application.jokeurl}")
private String jokeUrl;
@Value("${application.joke-url}")
private String jokeDashUrl;
@Test
void contextLoads() {
System.out.println(jokeUrl);
System.out.println(jokeDashUrl);
}
}
And here's my application.yml
:
application:
joke-url: url1 #pay attention to dash in property name
When I run the test it prints two lines into the console:
url1
url1
We see that Spring injects the same String into Values referencing in fact different properties, i.e. @Value("${application.jokeurl}")
and @Value("${application.joke-url}")
.
Now if I add one more property into application.yml
as
application:
joke-url: url1 #pay attention to dash in property name
jokeurl: url2 #no dash in property name
the same test prints different lines:
url2
url2
Now we see that the property application.joke-url
is ignored in favor of application.jokeurl
and again injects the same String into Values referencing different properties.
So my question is whether this is a bug or expected behavior?
Spring Boot follows the concept of Relaxed Binding
. The concept states:
Simple properties are bound by removing any special characters and converting to lowercase.
In your case, application.joke-url
property via Relaxed Binding becomes application.jokeurl
. The value of joke-url
property is replaced by jokeurl
property because they are same property as per that concept.
That's why you are facing the issue.
FYI: Spring Boot will not throw any warnings/errors as this is an expected behavior.
Solution:
The trick is not use any special characters for simple properties.
Use camelcase. Change jokeurl
to jokeUrl
to fix your issue.
application.yml or application.yaml:
application:
joke-url: url1
jokeUrl: url2
Updated DemoApplicationTests:
@SpringBootTest
class DemoApplicationTests {
@Value("${application.jokeUrl}")
private String jokeUrl;
@Value("${application.joke-url}")
private String jokeDashUrl;
@Test
void contextLoads() {
System.out.println(jokeUrl);
System.out.println(jokeDashUrl);
}
}
Output :
url2
url1
Tested with JDK 21 and Spring Boot 3.1.4. It's working.