5

I got a data.yml in resources folder of a following structure:

main:
  header:
    info: 3600L

I use Spring Boot version 2.4.2, I want to inject property main.header1.info to a field, I do this the following way:

@Component
@PropertySource("classpath:data.yml")
public class SomeClass {
    @Value("`main.header1.info")
    private long info;
    ...
}

But a NumberFormatException ocurres:

java.lang.NumberFormatException: For input string: "main.header1.info"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:na]
    at java.base/java.lang.Long.parseLong(Long.java:692) ~[na:na]
    ...

I know that long is not supported in yml, but I think its not the case. I tried other numeric types and corresponding wrapper-classes, like Double. So, how to fix that?

majorMobilych
  • 95
  • 2
  • 6

4 Answers4

2

You have to use ${main.header.info} to inject the value from properties. @PropertySource doesn't support the loading of .yaml or yml files. Try to use .properties file for loading them using @PropertySource.

There was an issue opened for this but Spring guys closed it. Many developers opposed and were unhappy with this. They still demanded to re-open this issue.

Instead create data.properties file.

main.header.info=3600L

Modify the code to this :

@Component
@PropertySource("classpath:data.properties")
public class SomeClass {
    @Value("${main.header1.info}")
    private long info;
    ...
}
Anish B.
  • 9,111
  • 3
  • 21
  • 41
2

I recommend using application.yml file inspite of custom YAML file.

Reason : application.properties is spring's default config file. If you use it, you don't have to worry about loading the file to context manually as spring takes care of it. But, In you case, you are trying to load and read value from a custom YAML file. So, @PropertySource won't help here.

Refer to the spring-docs for details about YAML Shortcomings.

However if you still wish to read values from a custom yaml, You will need to write a custom class ( Ex : CustomYamlPropertySourceFactory ) which implements PropertySourceFactory & inform @PropertySource to use this factory class.

Reference Code :

    @Component
    @PropertySource(value = "classpath:date.yml", factory = CustomYamlPropertySourceFactory.class) 
    public class SomeClass {

    @Value("${main.header.info}")
    private int info;
}
Amit kumar
  • 2,169
  • 10
  • 25
  • 36
2

For those out there who due to constraints cannot use an application.properties files and need the properties provided as a YAML file:

As many answers say here, there is no default way for Spring to parse YAML property files. The default DefaultPropertySourceFactory implementation is only capable of parsing .properties and .xml files.

You need to create a custom factory class implementing PropertySourceFactory to let the framework know how to parse a specific configuration source.

Here is a basic example on how to do that:

public class YamlPropertySourceFactoryExample implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(final String name, final EncodedResource resource) throws IOException {
        final Properties propertiesFromYaml = loadYamlIntoProperties(resource);
        final String sourceName = name != null ? name : resource.getResource().getFilename();
        return new PropertiesPropertySource(sourceName, propertiesFromYaml);
    }

    private Properties loadYamlIntoProperties(final EncodedResource resource) {

        final YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(resource.getResource());
        factory.afterPropertiesSet();
        return factory.getObject();
    }
}

With it you are accomplishing two things:

  • Loading the YAML configurations into a Properties object.
  • Returning a PropertiesPropertySource object which wraps the loaded Properties.

After that you can reference it in a factories atribute of any @PropertyResource:

    @PropertySource(value = "classpath:path/to/your/properties.yml", factory = YamlPropertySourceFactoryExample.class) 

Edit: It cannot be used with @TestPropertySource, it does not support any factories at the moment.

Miguel Ruiz
  • 408
  • 1
  • 6
  • 13
1

You cannot use a yml file with @PropertySource.

YAML files cannot be loaded by using the @PropertySource annotation. So, in the case that you need to load values that way, you need to use a properties file.

See YAML Shortcomings documentation.

Cisco
  • 20,972
  • 5
  • 38
  • 60