Spring Boot - YML config - Erase entry when mergin

2019-08-20 04:51发布

问题:

I have a base YML config for my app, in the class path that looks like this:

hello-world:
  values:
    bar:
      name: bar-name
      description: bar-description
    foo:
      name: foo-name
      description: foo-description

hello-world contains a map from string to POJO called values. I want to override the settings in hello-world, in particular I want to delete an entry. So on the local directory where I run the app I have this application.yml:

hello-world:
  values:
    bar:
      name: bar-name
      description: bar-description

source: from-the-local-dir

But this doesn't work, because when my local config overrides the existing one, the maps are merged into one and the original entry "foo" is kept. Is there a way to explicitly delete entries from a config map in spring yml?

PS: I can see that the local file get picked up, by modifying the the "bar" entry in the local file. Here's the full code, I've added a "source" config to tell which file was loaded last:

@Import(PlayGround.Config.class)
@SpringBootApplication
public class PlayGround {

    @Autowired
    Config config;

    @Value("${source}")
    String source;

    public void start() {
        System.out.println(config);
        System.out.println(source);
    }

    public static void main(String[] args) {
        System.out.println(Arrays.toString(args));
        ConfigurableApplicationContext context = SpringApplication.run(PlayGround.class, args);
        PlayGround playGround = context.getBean(PlayGround.class);
        playGround.start();
    }

    @ConfigurationProperties(prefix = "hello-world")
    public static final class Config {
        Map<String, Information> values = new HashMap<String, Information>();

        public Map<String, Information> getValues() {
            return values;
        }

        public void setValues(Map<String, Information> values) {
            this.values = values;
        }

        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this)
                    .add("values", values)
                    .toString();
        }
    }

    public static final class Information {

        String name;
        String description;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this)
                    .add("name", name)
                    .add("description", description)
                    .toString();
        }
    }

}

回答1:

Spring boot by default takes file from src/main/resource/application.yml You can declare config/application.yml and those config will override application.yml in src/main/resources

You can just try src/main/resources/application.yml:

hello-world:
  bar: 
    name: bar-name
    description: bar-description
  foo: 
    name: foo-name
    description: foo-description

And config/application.yml

  hello-world:
      bar: 
        name: bar-name
        description: bar-description

I think this can help So when you will run your application config/application.yml will override your existing src/main/resources/application.yml

You can completely remove hello-world from config/application.yml But it will throw a runtime exception something like :

Could not resolve placeholder 'hello-world.foo' in value "${hello-world.foo}

To fix it you can apply injecting value like: @Value("${hello-world.foo:}") where after ':' you can define default value

You can leave in config/application.yml empty fields

hello-world:
  bar: 
    name: bar-name
    description: bar-description
  foo: 
    name:
    description:

By default if you will not specify all values in foo will be empty('') and then you can filter and remove entry with empty values from your map. Also you can look into this class:

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/YamlProcessor.ResolutionMethod.html