Home > Net >  Reading custom objects from additional YAML in Spring Boot
Reading custom objects from additional YAML in Spring Boot

Time:09-21

I have a task of reading settings from a YAML file in a Spring Boot application. The requirement is that these settings are stored in a specific file, separate from application.yml. The file is called applicationFeatureToggles.yml and is supposed to have contents like these:

features:
  - key: feature1
    isEnabled: false
    description: First feature
  - key: feature2
    isEnabled: true
    description: Second feature
...

What I need to implement right now is to check in my components' code if a specific feature is enabled. To do this, I created a class for a single feature:

@NoArgsConstructor
@Getter
@Setter
public class Feature {
    private String key;
    private boolean isEnabled;
    private String description;
}

then a configuration properties class to store all settings:

@Component
@ConfigurationProperties
@PropertySource(value = "classpath:applicationFeatureToggles.yml", factory = YamlPropertySourceFactory.class)
public class FeatureProperties {
    private List<Feature> features;
    
    // Constructor, getters and setters
}

and a service that uses it to check if a feature is enabled:

@Service
@EnableConfigurationProperties(FeatureProperties.class)
public class FeatureService {

    @Autowired
    private FeatureProperties featureProperties;

    // logic that reads required info from featureProperties
}

The class YamlPropertySourceFactory used in FeatureProperties looks like this:

public class YamlPropertySourceFactory implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(resource.getResource());

        Properties properties = factory.getObject();

        return new PropertiesPropertySource(resource.getResource().getFilename(), properties);
    }
}

As I understand, this should result in FeatureService having access to FeatureProperties populated with data from applicationFeatureToggles.yml, but the data is missing. At the same time, I checked with a breakpoint that YamlPropertySourceFactory is invoked and reads the data, it's present in the properties object before exiting createPropertySource(). So all seems fine with reading properties from the file, but they don't get into the FeatureProperties object.

What else can my code need to populate FeatureProperties?

If it's not possible at all or can cause some other issues, I'd also be thankful for details, as it may help convince the architect to change the approach.

Spring Boot version used: 2.5.6

CodePudding user response:

I have found the cause. One other thing I did in my code was calling FeatureService in an SpEL expression in a @Conditional for another bean. So it seems FeatureService tried to initialize before FeatureProperties. Without this condition, FeatureService gets proper FeatureProperties.

I think I will eventually find a workaround now, but would be thankful if someone knows how to conditionally initialize a bean depending on some ConfigurationProperties if it also involves some logic to process the configs.

CodePudding user response:

What else can my code need to populate FeatureProperties?

Your approach is correct, what you need is setters and getters for FeatureProperties class

@Component
@ConfigurationProperties
@PropertySource(value = "classpath:applicationFeatureToggles.yml", factory 
= YamlPropertySourceFactory.class)
@Getter
@Setter
public class FeatureProperties
{
     private List<Feature> features;
}
  • Related