Reputation: 3612
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:
mvn spring-boot:run
: Prints [foo, bar, baz]
as expected.ENVTESTING_LIST=newfoo,newbar mvn spring-boot:run
: Prints [newfoo, newbar]
. This is fine, since the whole list is being replaced.ENVTESTING_LIST_0=newfoo ENVTESTING_LIST_1=newbar mvn spring-boot:run
: Prints [newfoo, newbar]
. Expected it to print [newfoo, newbar, baz]
since only the elements are being replaced, but it seems to be creating a whole new list.ENVTESTING_LIST_0=newfoo mvn spring-boot:run
: Prints [newfoo]
. Same issue as above.ENVTESTING_LIST_1=newbar mvn spring-boot:run
: Throws error. Expected it to print [foo, newbar, baz]
.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
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