Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manipulating configuration properties in spring

I'm looking for a way to manipulate @ConfigurationProperties defined on initialization so that when I @Inject / @Autorwired the configured object using a @Bean method it is properly configured.

Scenario:

I have a bunch of properties set in a .yml file. Because all of these properties match as Strings some of them need special handling to be properly configured to their respective types (some of them are enums). Do I make my properties object a @Component then inject it into the @Bean method and modify it? I tried to combine @Bean and @ConfigurationProperties annotations but the object is configured AFTER the @Bean method itself returns, so any manipulation is lost/impossible. What is the best way to do this?

Example: In my .yml i have this:

properties:
  sports:
    "football": ["Team 1", "Team 2", "Team 3"]
    "basketball": ["Team 4", "Team 5", "Team 6"]
  settings:
    "football":
      "period1": "45"
      "period2": "90"
      "players": "11"
    "basketball":
      "periods": "4"
      "players": "5"

And these match with the following objects:

Map<SportsEnum, List<TeamsEnum>
Map<SportsEnum, Map<SportSettingsEnum, String>>

TL;DR: I want to take an object configured from a .yml/.properties file and manipulate its injectable representation. Please provide concrete example!

like image 808
PentaKon Avatar asked Jul 26 '16 07:07

PentaKon


1 Answers

This is definitely supported, my guess is that you're doing something wrong. Let's go step by step.

First, your YAML file is badly formatted, it should look something like this:

properties:
  sports:
    football:
      - Team1
      - Team2
      - Team3
    basketball:
      - Team4
      - Team5
      - Team6
  settings:
    football:
      period1: 45
      period2: 90
      players: 11
    basketball:
      periods: 4
      players: 5

Then, your configuration properties would look like this:

@ConfigurationProperties(prefix = "properties", locations = "classpath:sports.yml")
public class SportsProperties {

    private Map<SportsEnum, List<TeamsEnum>> sports;
    private Map<SportsEnum, Map<SportSettingsEnum, String>> settings;

    public Map<SportsEnum, List<TeamsEnum>> getSports() {
        return sports;
    }

    public void setSports(Map<SportsEnum, List<TeamsEnum>> sports) {
        this.sports = sports;
    }

    public Map<SportsEnum, Map<SportSettingsEnum, String>> getSettings() {
        return settings;
    }

    public void setSettings(
        Map<SportsEnum, Map<SportSettingsEnum, String>> settings) {
        this.settings = settings;
    }

    @PostConstruct
    public void customManipulation() {
        System.out.println(sports);
        System.out.println(settings);
    }
}

Next, the properties should be enabled in your configuration:

@SpringBootApplication
@EnableConfigurationProperties(SportsProperties.class)
public class YamlSampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(YamlSampleApplication.class, args);
    }

}

That should be it, really. Here are my enums:

public enum SportsEnum {
    football, basketball
}

public enum TeamsEnum {
    Team1, Team2, Team3, Team4, Team5, Team6
}

public enum SportSettingsEnum {
    periods, period1, period2, players
}

Here's the output I get in the logs:

2016-07-26 17:44:41.226 DEBUG 30015 --- [           main] s.b.e.YamlPropertySourceLoader$Processor : Loading from YAML: class path resource [sports.yml]
2016-07-26 17:44:41.282 DEBUG 30015 --- [           main] s.b.e.YamlPropertySourceLoader$Processor : Matched document with default matcher: {properties={sports={football=[Team1, Team2, Team3], basketball=[Team4, Team5, Team6]}, settings={football={period1=45, period2=90, players=11}, basketball={periods=4, players=5}}}}
2016-07-26 17:44:41.282 DEBUG 30015 --- [           main] s.b.e.YamlPropertySourceLoader$Processor : Loaded 1 document from YAML resource: class path resource [sports.yml]
{football=[Team1, Team2, Team3], basketball=[Team4, Team5, Team6]}
{football={period1=45, period2=90, players=11}, basketball={periods=4, players=5}}
like image 152
Miloš Milivojević Avatar answered Oct 07 '22 05:10

Miloš Milivojević