I've following problem.

I've an instance with following active profiles: dev, test, foo

and apllication-test.yaml file

---
my.prop1: default
my.prop2: default
---
spring.profiles: dev
my.
    prop1: dev
    prop3: abc
---
spring.profiles: foo
my.prop2: foo

My intuition would tell me: my.prop1 = dev my.prop2 = foo

Thought the result is really: my.prop1 = default my.prop2 = foo

It seems to use the order of profiles, rather then the order of the document. This seems to be different then what the documentation is saying. (Correct me if I'm wrong)

Further more my.prop3 seems to be not set at all as if this section is ignored even if dev is set active.

Is this a bug of Spring or is there a trick to it?

lG Lukas

Comment From: wilkinsona

Sorry, I'm finding it a little hard to follow your description of the problem. Can you please provide a small sample that reproduces the problem so that we can be sure we're investigating the right thing?

Comment From: LProemer

I'm sorry, my english isn't that good. I do my best to give a good example.

Basically the problem is simple:
When you have an "application-bar.yaml", And spring.profiles.active is set to "foo, bar" Then the sub-section inside the yaml file where "spring.profiles: foo" is set, is ignored.

application.properties: spring.profiles.active = foo, bar, abc

application-bar.yaml

---
// default values
my.var: 1                   
other.var: 1               
---
spring.profiles: foo   
my.var: 2                  // is ignored, even thought profile foo is set
---
spring.profiles: abc 
other.var: 2             // is correctly applied 

Result: my.var = 1 other.var = 2

Does that help?

lG

Comment From: philwebb

I think this is related to c6bf13c0a121b9923c3b196f6dcd310084a5bca9 (issue #4132). Having profile specific sections in a profile specific file is a little unusual and I don't think we've considered this edge case.

Comment From: philwebb

@LProemer any specific reason you need to use application-bar.yaml to contain those extra sections?

Comment From: LProemer

The reason would be Feature-Configurations. The Feature is only enabled when the profile "bar" is set and should then configure it acording to the environment. We've tenths of configurations files and we've to start cleaning them up and simplyfy them. And using yaml-configurations like this would have been one way. Thought I'm aware that they are other ways to work around this problems.

Comment From: shakuzen

I also ran into this problem and it took quite some time to track it down and figure out why it was happening. My use case is that we have configuration properties specific to logical environments (say dev, stg, prod) and that we want to be active only when the application is running on our platform (Cloud Foundry as cloud profile; or our other platform that uses the server profile) as opposed to a developer's machine. The assumption being a developer might activate a logical environment profile from her or his machine but would not activate cloud or server.

Therefore, to achieve this, it seemed reasonable to me to put say the DEV environment spring.boot.admin.client.uri in a file application-dev.yml like:

---
spring:
  profiles: cloud,server

  boot.admin.client.uri: http://my-admin-url

The above works fine, actually, if the active profiles are in the "right" order dev,cloud, but it does not work if the order is cloud,dev. This can also be demonstrated by the following change to an existing Spring Boot test (switch the order of the active profiles):

===================================================================
--- spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java   (revision 3ae4a541b630fb7bccf45ebd0922c19d099c2276)
+++ spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java   (date 1521006994000)
@@ -777,7 +777,7 @@
        SpringApplication application = new SpringApplication(Config.class);
        application.setWebApplicationType(WebApplicationType.NONE);
        this.context = application.run(
-               "--spring.profiles.active=activeprofilewithdifferentsubdoc,activeprofilewithdifferentsubdoc2");
+               "--spring.profiles.active=activeprofilewithdifferentsubdoc2,activeprofilewithdifferentsubdoc");
        String property = this.context.getEnvironment().getProperty("foobar");
        assertThat(property).isEqualTo("baz");
    }

https://github.com/spring-projects/spring-boot/blob/3ae4a541b630fb7bccf45ebd0922c19d099c2276/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java#L774-L783

I've also pushed a repro project with a failing test case: https://github.com/shakuzen/demo-compound-profile

To summarize the use case, being able to use sub-documents in YAML files that are themselves profiled allows for AND semantics. In the example shown above, the dev profile AND the cloud (OR server) profile should be active for the property source to be included. #12469 was raised recently also regarding AND profile matching semantics. What I find nice about what I expected to work (and does if the active profile order is "right") is that it allows one AND and an arbitrary number of ORs. Perhaps the outcome of SPR-12458 will pave a way for something more robust.

For my specific use case mentioned above, we can work around this thanks to Spring Boot Admin client offering an enabled property that we can set to false by default and only make it true when the cloud OR server profile is active. Perhaps there are other use cases that aren't as easily worked around. At the least, the behavior was hard to understand and surprising.

Comment From: mbhave

This should be solved by config data rewrite in 2.4.x. For multi-document files, later documents can override the properties defined in earlier ones. With the following configuration in application-test.yml and active profiles of dev, foo, test,

---
my.prop1: default
my.prop2: default
---
spring.profiles: dev
my.
    prop1: dev
    prop3: abc
---
spring.profiles: foo
my.prop2: foo

the result is

my.prop1 = dev my.prop2 = foo my.prop3 = abc