Munir
Munir

Reputation: 3612

Springboot properties - update only selected elements in a list

I have a Springboot application which accepts a list of strings as one of the properties. I want to configure it such that some items of the list may come from environment variables, and some may come from the application.yaml file. My tests with an MVCE indicate that if I try to update any element of the list using an environment variable, Spring will replace the entire list regardless of the other items defined later.

Simple test class

import lombok.Data;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@SpringBootApplication
public class Main {

  @Data
  @Component
  @ConfigurationProperties(prefix = "envtesting")
  public static class AppProperties {
  
    private List<String> list = new ArrayList<>();  
  }

  @Component
  @Configuration
  public static class AppConfiguration {

    @Bean
    public List<String> props(AppProperties appProperties) {
      System.out.println(appProperties.getList());
      return appProperties.getList();
    }
  }


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

My application.yaml file

envtesting:
  list:
    - foo
    - bar
    - baz

These are the outputs I get with various commands:

Is there a way to make this behave the way I want it to? Maybe by overriding some method or by using some annotation on the list property?

Upvotes: 1

Views: 554

Answers (1)

Munir
Munir

Reputation: 3612

Spring combines maps but not lists. So here's the hacky workaround I came up with.

  public static class AppProperties {
  
    private Map<Integer, String> map = new HashMap<>();  
  }

  @Component
  @Configuration
  public static class AppConfiguration {

    @Bean
    public Collection<String> props(AppProperties appProperties) {
      return appProperties.getMap().values();
    }
  }

This works for me since I do not care about the order of the entries. If the order matters, the map can be sorted before returning.

Upvotes: 1

Related Questions