Search code examples
javaspringspring-bootyaml

Spring Boot ignores dashes in property names in YML files


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?


Solution

  • 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.